home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / Technical Documentation / develop / develop Issue 24 / develop Issue 24 code / Scriptable Database 1.0a15 / Foundation / AbstractScriptableObject.cp < prev    next >
Encoding:
Text File  |  1996-02-19  |  106.7 KB  |  3,044 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        AbstractScriptableObject.c
  3.  
  4.     Contains:    Abstract Scriptable Object support
  5.  
  6.     Written by:    Greg Anderson
  7.  
  8.     Copyright:    © 1993-1995 by Apple Computer, Inc, all rights reserved.
  9.  
  10.         <31>     9/26/95    pco        
  11. */
  12.  
  13. #ifdef MWTRACEBACKTABLES
  14. #pragma traceback on
  15. #endif
  16.  
  17.  
  18. #include "AbstractScriptableObject.h"
  19.  
  20. //
  21. // Lists of abstract scriptable objects
  22. //
  23. #include "ScriptableObjectList.h"
  24.  
  25. //
  26. // Mark tokens are needed to silently union together multiple
  27. // matches in AccessByName
  28. //
  29. #include "MarkToken.h"
  30.  
  31. //
  32. // EveryItemProxy is needed to handle kAEAll in AccessByOrdinal
  33. // and pContents in AccessByProperty
  34. //
  35. #include "EveryItemProxy.h"
  36.  
  37. //
  38. // Entire contents is needed to handle pEntireContents in AccessByProperty
  39. //
  40. #include "EntireContents.h"
  41.  
  42. //
  43. // Collectors are needed in AccessBySearchSpec
  44. //
  45. #include "AbstractCollector.h"
  46.  
  47. //
  48. // AbstractSearchSpec is needed to resolve whose descriptors
  49. // in ParseWhoseDescriptor, ParseLogicalDescriptor & c.
  50. //
  51. #include "AbstractSearchSpec.h"
  52.  
  53. //
  54. // GenericSearchSpec is needed because we will create a
  55. // generic search specification CreateSearchSpecification 
  56. // to cover cases where the class derived from TAbstractScriptableObject
  57. // does not know how to create an optimized specification
  58. //
  59. #include "GenericSearchSpec.h"
  60.  
  61. //
  62. // Comparison operands are needed to make a generic search spec.
  63. //
  64. #include "ComparisonOperand.h"
  65.  
  66. //
  67. // Comparison operands might be object specifiers that we need to
  68. // resolve (recursively)
  69. //
  70. #include "ResolveObjectSpecifier.h"
  71.  
  72. //
  73. // We will sometimes be asked to retrieve "any" item,
  74. // in which case we will need to generate random numbers.
  75. //
  76. #include "PseudoRandom.h"
  77.  
  78. //
  79. // We include FinderRegistry to get pEntireContents.
  80. // This is somewhat undesirable; we should move
  81. // pEntireContents to some other .h file.
  82. //
  83. // #include "FinderRegistry.h"
  84. #define pEntireContents            'ects'
  85. #define pProperties                'prps'                // The "properties" property
  86.  
  87. #include <AERegistry.h>
  88. #include <AEObjects.h>
  89.  
  90. //
  91. // For memcpy
  92. //
  93. //#include <string.h>
  94.  
  95. #include "Exceptions.h"
  96.  
  97. #include "Debug.h"
  98.  
  99.  
  100.  
  101. //========================================================================================
  102. // CLASS TClassPropertyInfo
  103. //========================================================================================
  104.  
  105. //----------------------------------------------------------------------------------------
  106. // TClassPropertyInfo::PropertyExists
  107. //----------------------------------------------------------------------------------------
  108. Boolean TClassPropertyInfo::PropertyExists(unsigned long propertyName) const
  109.     {
  110.     long i = 0;
  111.     
  112.     if(fArrayOfPropertyIdentifiers != nil)
  113.         {
  114.         while(fArrayOfPropertyIdentifiers[i].PropertyIdentifier() != 0)
  115.             {
  116.             if(fArrayOfPropertyIdentifiers[i].PropertyIdentifier() == propertyName)
  117.                 return true;
  118.             
  119.             ++i;
  120.             }
  121.         }
  122.         
  123.     return false;
  124.     } // TClassPropertyInfo::PropertyExists
  125.     
  126. //----------------------------------------------------------------------------------------
  127. // TClassPropertyInfo::DescriptionOfProperty
  128. //----------------------------------------------------------------------------------------
  129. const TPropertyDescription* TClassPropertyInfo::DescriptionOfProperty(unsigned long propertyName) const
  130.     {
  131.     long i = 0;
  132.  
  133.     if(fArrayOfPropertyIdentifiers != nil)
  134.         {    
  135.         while(fArrayOfPropertyIdentifiers[i].PropertyIdentifier() != 0)
  136.             {
  137.             if(fArrayOfPropertyIdentifiers[i].PropertyIdentifier() == propertyName)
  138.                 return &fArrayOfPropertyIdentifiers[i];
  139.             
  140.             ++i;
  141.             }
  142.         }
  143.     
  144.     return nil;
  145.     } // TClassPropertyInfo::DescriptionOfProperty
  146.     
  147. //----------------------------------------------------------------------------------------
  148. // TClassPropertyInfo::NumberOfProperties
  149. //----------------------------------------------------------------------------------------
  150. long TClassPropertyInfo::NumberOfProperties() const
  151.     {
  152.     return fPropertyCount;
  153.     } // TClassPropertyInfo::NumberOfProperties
  154.     
  155. //----------------------------------------------------------------------------------------
  156. // TClassPropertyInfo::DescriptionOfNthProperty
  157. //----------------------------------------------------------------------------------------
  158. const TPropertyDescription* TClassPropertyInfo::DescriptionOfNthProperty(long propertyNumber) const
  159.     {
  160.     //
  161.     // We reverse the order in which we return the properties because the
  162.     // order of iteration is usually reversed, and we want the first items
  163.     // in the list to appear first in the results.
  164.     //
  165.     if(propertyNumber < fPropertyCount)
  166.         return &fArrayOfPropertyIdentifiers[(fPropertyCount - propertyNumber) - 1];
  167.     else
  168.         return nil;
  169.     }
  170.  
  171.  
  172. //========================================================================================
  173. // CLASS TAbstractScriptableObject
  174. //========================================================================================
  175.  
  176. //
  177. // Note:  In addition to the properties described below, TAbstractScriptableObject
  178. // also defines pContents and pEntireContents.  These are not advertised as properties,
  179. // though, as they behave more like accessors and would probably interfere with
  180. // requests to get every property of an object (you probably wouldn't want to see the
  181. // object's contents or entire contents at that time, and you certainly wouldn't want
  182. // to see both!)
  183. //
  184. TPropertyDescription TAbstractScriptableObject::fPropertiesOfClass[] = {
  185.     {    pName,            0,                                            typeChar,            typeChar            },
  186.     {    pClass,            kDontIncludeInPropertiesProperty,            typeType,            typeType            },
  187.     {    pDefaultType,    kDontIncludeInPropertiesProperty,            typeType,            typeType            },
  188.     {    pBestType,        kDontIncludeInPropertiesProperty,            typeType,            typeType            },
  189.     {    pID,            0,                                            typeLongInteger,    typeLongInteger        },
  190.     {    pIndex,            kDontIncludeInPropertiesProperty,            typeLongInteger,    typeLongInteger        }
  191. };
  192.  
  193. #pragma segment ObjectResident
  194. ImplementClassData(TAbstractScriptableObject, clScriptableObject);
  195.  
  196. #pragma segment Foundation
  197.  
  198. //----------------------------------------------------------------------------------------
  199. // TAbstractScriptableObject::TAbstractScriptableObject: 
  200. //----------------------------------------------------------------------------------------
  201. TAbstractScriptableObject::TAbstractScriptableObject()
  202.     {
  203.     } // TAbstractScriptableObject::TAbstractScriptableObject 
  204.  
  205. //----------------------------------------------------------------------------------------
  206. // TAbstractScriptableObject::~TAbstractScriptableObject: 
  207. //----------------------------------------------------------------------------------------
  208. TAbstractScriptableObject::~TAbstractScriptableObject()
  209.     {
  210.     } // TAbstractScriptableObject::~TAbstractScriptableObject 
  211.  
  212. //----------------------------------------------------------------------------------------
  213. // TAbstractScriptableObject::IAbstractScriptableObject: 
  214. //----------------------------------------------------------------------------------------
  215. void TAbstractScriptableObject::IAbstractScriptableObject()
  216.     {
  217. #ifdef DEBUG
  218.     //
  219.     // Look up the class ID of this object as soon as we are constructed
  220.     // so that we can initialize the debugging information in TObject.
  221.     //
  222.     this->ClassID();
  223. #endif
  224.     } // TAbstractScriptableObject::IAbstractScriptableObject 
  225.  
  226. //
  227. // Comment out operator equal for now
  228. //
  229. #ifdef OPEQU
  230.  
  231. //----------------------------------------------------------------------------------------
  232. // TAbstractScriptableObject::operator=: 
  233. //----------------------------------------------------------------------------------------
  234. TAbstractScriptableObject& TAbstractScriptableObject::operator=(const TAbstractScriptableObject& rhs)
  235.     {
  236.     BlockMoveData((Ptr)&rhs, (Ptr)this , sizeof(*this));    // ••• sizeof this sucks
  237.     return *this;
  238.     } // TAbstractScriptableObject::operator= 
  239.  
  240. #endif
  241.  
  242. //----------------------------------------------------------------------------------------
  243. // TAbstractScriptableObject::IsDesignator: 
  244. //
  245. // This virtual method is overridden by TAbstractDesignator, so that clients dealing
  246. // with a token can identify designators.  This is necessary because the memory ownership
  247. // rules are different for designators than non-designators; see 'CloneDesignator' and
  248. // 'DisposeDesignator' for more information.
  249. //----------------------------------------------------------------------------------------
  250. Boolean TAbstractScriptableObject::IsDesignator()
  251.     {
  252.     return false;
  253.     } // TAbstractScriptableObject::IsDesignator 
  254.  
  255. //----------------------------------------------------------------------------------------
  256. // TAbstractScriptableObject::DisposeDesignator: 
  257. //
  258. // Whenever a method of TAbstractScriptableObject returns a pointer to another
  259. // TAbstractScriptableObject (e.g. Parent(), AccessByIndex() and Create()), the
  260. // client code must always call DisposeDesignator when it is done using the object.
  261. // This is because the TAbstractScriptableObject returned might actually be
  262. // a _designator_ to some other TAbstractScriptableObject (e.g. a class that
  263. // designates a range of characters within a text object).  The designator is not
  264. // an object itself--it is only created to specify some subset of another object,
  265. // and its lifetime is limited to the local set of code that specifically referenced
  266. // the aforementioned subset of an object.
  267. //
  268. // Properties of objects are designators--they do not represent the entire object
  269. // that they are a property of; instead, they designate one aspect of the object
  270. // (such as its name, its size, or its best data type).
  271. //----------------------------------------------------------------------------------------
  272. void TAbstractScriptableObject::DisposeDesignator()
  273.     {
  274.     if(this->IsDesignator())
  275.         delete this;
  276.     } // TAbstractScriptableObject::DisposeDesignator 
  277.  
  278. //----------------------------------------------------------------------------------------
  279. // TAbstractScriptableObject::CloneDesignator:
  280. //
  281. // This is the inverse method of DisposeDesignator; any routine that returns a designator
  282. // must return a _copy_ of any existing designator.  This routine will do the right thing
  283. // and return a reference to non-designators, and a copy of designators.
  284. //----------------------------------------------------------------------------------------
  285. TAbstractScriptableObject* TAbstractScriptableObject::CloneDesignator()
  286.     {
  287.     if(this->IsDesignator())
  288.         return (TAbstractScriptableObject*)this->Clone();
  289.     else
  290.         return this;
  291.     } // TAbstractScriptableObject::CloneDesignator 
  292.  
  293. //----------------------------------------------------------------------------------------
  294. // TAbstractScriptableObject::ObjectClass: 
  295. //
  296. // The class of the object; for example, the Scriptable Finder knows about items of
  297. // class cFile, cFolder, cDisk, cTrash, cAlias, cApplicationFile, cSoundFile, and
  298. // quite a few others.
  299. //
  300. // TAbstractScriptableObject::ObjectClass is pure-virtual, and must be overridden
  301. // by all derived classes.
  302. //
  303. // The recorded class is the class that is returned by BuildObjectSpecifier.  Although a scriptable
  304. // application will usually know about many different classes of things (see the list
  305. // of examples given for ObjectClass, above), it should be more general when returning
  306. // object specifiers for its objects, just in case some other application that isn't
  307. // quite as smart as yours would like to parse them.  For example, the Scriptable Finder
  308. // only tends to use the classes cFile, cFolder and cDisk when returning specifiers;
  309. // there is no need for most applications to have to deal with 'cSoundFile'.
  310. //----------------------------------------------------------------------------------------
  311. DescType TAbstractScriptableObject::ObjectClass(const TAETransaction&, Boolean /*recordedClass = false*/)
  312.     {
  313.     return typeWildCard;
  314.     } // TAbstractScriptableObject::ObjectClass 
  315.  
  316. //----------------------------------------------------------------------------------------
  317. // TAbstractScriptableObject::DerivedFromOSLClass: 
  318. //----------------------------------------------------------------------------------------
  319. Boolean TAbstractScriptableObject::DerivedFromOSLClass(const TAETransaction&, DescType objectClass)
  320.     {
  321.     return objectClass == typeWildCard;
  322.     } // TAbstractScriptableObject::DerivedFromOSLClass 
  323.  
  324. //----------------------------------------------------------------------------------------
  325. // TAbstractScriptableObject::Exists: 
  326. //
  327. // Most tokens exist if they were created in the first place.  Exceptions include the
  328. // selection, which claims not to exist if there are no selected objects.
  329. //----------------------------------------------------------------------------------------
  330. Boolean TAbstractScriptableObject::Exists(const TAETransaction&)
  331.     {
  332.     return true;
  333.     } // TAbstractScriptableObject::Exists 
  334.  
  335. //----------------------------------------------------------------------------------------
  336. // TAbstractScriptableObject::DirectObjectIterator
  337. //----------------------------------------------------------------------------------------
  338. TAbstractObjectIterator* TAbstractScriptableObject::DirectObjectIterator(const TAETransaction&)
  339.     {
  340.     return new TSingleObjectIterator(this);
  341.     } // TAbstractScriptableObject::DirectObjectIterator
  342.  
  343. //----------------------------------------------------------------------------------------
  344. // TAbstractScriptableObject::ConvertThisToList
  345. //
  346. // For a single scriptable object, this method returns a list with one element.
  347. // For collection classes, this method returns all of the elements of the collection
  348. // in a list.
  349. //----------------------------------------------------------------------------------------
  350. AListOf<TAbstractScriptableObject*>* TAbstractScriptableObject::ConvertThisToList(const TAETransaction& t, DescType useRepresentative /* = 0 */)
  351.     {
  352.     TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  353.     AListOf<TAbstractScriptableObject*>* itemList = new AListOf<TAbstractScriptableObject*>(iter->CountElements(t, typeWildCard));
  354.     TAbstractScriptableObject* token = nil;
  355.     
  356.     for(iter->Reset(t); iter->More(t); iter->Next(t))
  357.         {
  358.         token = iter->Current(t);
  359.         if(token->SendCommandToRepresentative(t, useRepresentative))
  360.             {
  361.             TAbstractScriptableObject* ownerOfRepresentative = token;
  362.             token = ownerOfRepresentative->RepresentativeScriptingObject(t);
  363.             ownerOfRepresentative->DisposeDesignator();
  364.             }
  365.         itemList->Add(token);
  366.         }
  367.     iter->Release();
  368.     
  369.     return itemList;
  370.     } // TAbstractScriptableObject::ConvertThisToList
  371.  
  372. //----------------------------------------------------------------------------------------
  373. // TAbstractScriptableObject::ObjectRepresentedInToken: 
  374. //
  375. // Returns true if 'objectToTestForMembership' is one of the objects represented by
  376. // this token.  Trivial for the base case (comaring one TIcon* with another, for
  377. // example), but see the implementation in TMarkToken for a better example.  One
  378. // example of the use of this method is in TSelectionToken, where setting the selection
  379. // tests to see if any of the currently selected items are in the list of items
  380. // that are about to be selected (usually represented by a TMarkToken).
  381. //
  382. // This function could be written in a non-virtual manner by calling
  383. // NumberOfTokenDirectObjects and GetIndexedTokenDirectObject, but that would
  384. // introduce two problems:  (1) Mark tokens that contained designators would then
  385. // be doing memory allocations and deallocations inside of an O(N^2) loop, and
  386. // (2) doing address comparisons on designators isn't particularly meaningful.
  387. // Currently, we don't need to do membership tests on designators, though.
  388. //----------------------------------------------------------------------------------------
  389. Boolean TAbstractScriptableObject::ObjectRepresentedInToken(const TAETransaction& t, TAbstractScriptableObject* objectToTestForMembership)
  390.     {
  391.     TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  392.     Boolean isContained = iter->Contains(t, objectToTestForMembership);
  393.     iter->Release();
  394.     
  395.     return isContained;
  396.     } // TAbstractScriptableObject::ObjectRepresentedInToken 
  397.  
  398. //----------------------------------------------------------------------------------------
  399. // TAbstractScriptableObject::ObjectsAreTheSame: 
  400. //----------------------------------------------------------------------------------------
  401. Boolean TAbstractScriptableObject::ObjectsAreTheSame(const TAETransaction&, TAbstractScriptableObject* objectToTest)
  402.     {
  403.     return (StripAddress((void*)((char*)this - (char*)objectToTest)) == 0);
  404.     } // TAbstractScriptableObject::ObjectsAreTheSame
  405.  
  406. //----------------------------------------------------------------------------------------
  407. // TAbstractScriptableObject::AdoptToken: 
  408. //----------------------------------------------------------------------------------------
  409. TAbstractScriptableObject* TAbstractScriptableObject::AdoptToken(TAbstractScriptableObject* token, TypeOfMarkToken markType)
  410.     {
  411.     TMarkToken* markToken = new TMarkToken(markType);
  412.     markToken->IMarkToken();
  413.     
  414.     //
  415.     // See the comment in AddThisToMarkToken, below, for a description of
  416.     // how this works.  This code is reached in 'case b', below.
  417.     // 'this' comes from 'markToken', and 'token' came from the contents of
  418.     // 'this' in AddThisToMarkToken.
  419.     //
  420.     markToken->AdoptToken(this, markType);
  421.     markToken->AdoptToken(token, markType);
  422.     
  423.     return markToken;
  424.     } // TAbstractScriptableObject::AdoptToken 
  425.  
  426. //----------------------------------------------------------------------------------------
  427. // TAbstractScriptableObject::AddThisToMarkToken: 
  428. //
  429. // On entry, 'markToken' can be nil, a single token (a TAbstractScriptableObject)
  430. // or a Mark token.  The desired behavior is:
  431. //
  432. //        a.    If markToken is nil on input, it equals 'this' on output
  433. //        b.    If markToken is a single TAbstractScriptable object on input, then
  434. //            it should be a TMarkToken on output, and its contents should be
  435. //            'markToken' (its value on input) and 'this'
  436. //        c.    If markToken is a TMarkToken, then this token should be added to
  437. //            it (as the name of this method implies).
  438. //
  439. // This method works in conjunction with TAbstractScriptableObject::AdoptToken.  A
  440. // double-dispatch is done to avoid doing a downcast to TMarkToken.  In 'case b',
  441. // above, TAbstractScriptableObject::AdoptToken will be called; it will create a
  442. // new TMarkToken and add markToken and this to it.  In 'case c', above,
  443. // TMarkToken::AdoptToken is called, which simply adds this token to the mark's
  444. // list of tokens, and returns the mark token back again.
  445. //
  446. // IMPORTANT:  This routine passes ownership of 'this' to the provided mark token.
  447. // This token might be deleted as a result (see TMarkToken::AddThisToMarkToken)!
  448. // Therefore, any code that calls AddThisToMarkToken must make sure not to reference
  449. // the token passed into the mark token after it is added to the mark list.
  450. //----------------------------------------------------------------------------------------
  451. void TAbstractScriptableObject::AddThisToMarkToken(TAbstractScriptableObject*& markToken, TypeOfMarkToken markType)
  452.     {
  453.     if(markToken == nil)
  454.         {        
  455.         //
  456.         // If the mark type indicates that we should always
  457.         // make a collection, then adopt a nil token to
  458.         // create a mark token with one element in it
  459.         //
  460.         if(markType == kAlwaysMakeCollection)
  461.             {
  462.             markToken = new TMarkToken(markType);
  463.             ((TMarkToken*)markToken)->IMarkToken();
  464.             markToken->AdoptToken(this, markType);
  465.             }
  466.         else
  467.             markToken = this;
  468.         }
  469.     else
  470.         {
  471.         markToken = markToken->AdoptToken(this, markType);
  472.         }
  473.     } // TAbstractScriptableObject::AddThisToMarkToken 
  474.  
  475. //----------------------------------------------------------------------------------------
  476. // TAbstractScriptableObject::ReturnReferencedObject: 
  477. //
  478. // This is for the benefit of objects derived from TAbstractReference, which should
  479. // override this method to return the actual object that is referenced.  Objects that
  480. // are not references return themselves (or a copy of themself).
  481. //----------------------------------------------------------------------------------------
  482. TAbstractScriptableObject* TAbstractScriptableObject::ReturnReferencedObject()
  483.     {
  484.     return this->CloneDesignator();
  485.     } // TAbstractScriptableObject::ReturnReferencedObject 
  486.  
  487. //----------------------------------------------------------------------------------------
  488. // TAbstractScriptableObject::CreateReference:
  489. //
  490. // An abstract reference is a lightweight representation of some scriptable object;
  491. // References are created when the object itself is large &/or slow to construct,
  492. // or to provide a portable (rather than application-specific) description of an object.
  493. //
  494. // For example, the Finder has HFS references that contain an FSSpec; these references
  495. // are used in place of full Finder-HFS objects when searching.
  496. //
  497. // Question:  Does this method really belong here?  References will never make
  498. // references to themselves, and I don't think that designators will ever have
  499. // references either.  Still, at this point it is somewhat unclear how specific
  500. // this method should be, so a very general base implementation is provided.
  501. //----------------------------------------------------------------------------------------
  502. TAbstractReference* TAbstractScriptableObject::CreateReference()
  503.     {
  504.     FailErr(errAEEventNotHandled);
  505.     return nil;
  506.     } // TAbstractScriptableObject::CreateReference 
  507.  
  508. //----------------------------------------------------------------------------------------
  509. // TAbstractScriptableObject::RepresentativeScriptingObject
  510. //
  511. // A representative scripting object, if provided, will be used to access
  512. // properties, elements & c. from a scriptable object if said object cannot
  513. // access the property itself.  For example, if much of the window scripting
  514. // code is contained in a window token class, the actual window object may
  515. // wish to create a window token to handle its script requests.
  516. // The method SendCommandToRepresentative controls which commands go to
  517. // your representative and which are sent to you.  (Question:  why not just
  518. // have TAbstractScriptableObject::Command send the command along if it
  519. // is not handled by the primary object?)
  520. //----------------------------------------------------------------------------------------
  521. TAbstractScriptableObject* TAbstractScriptableObject::RepresentativeScriptingObject(const TAETransaction&)
  522.     {
  523.     return nil;
  524.     }
  525.  
  526. //----------------------------------------------------------------------------------------
  527. // TAbstractScriptableObject::SendCommandToRepresentative
  528. //
  529. // Someday, perhaps, this will be virtual, but for now "reveal" is the only command
  530. // that we do not want to send to the object's representative. 
  531. //
  532. // n.b. Currently, TProxyToken::AECommandDispatch requires that any given
  533. // command either be sent to all of the representative objects or to none of them,
  534. // so that routine will need to be rewritten if this method allows each object to
  535. // decide if it will invoke its representative or not.
  536. //----------------------------------------------------------------------------------------
  537. Boolean TAbstractScriptableObject::SendCommandToRepresentative(const TAETransaction&, long aeCommandID)
  538.     {
  539.     return (aeCommandID != kAEMakeObjectsVisible) && (aeCommandID != 0);
  540.     } // TAbstractScriptableObject::SendCommandToRepresentative
  541.     
  542. //----------------------------------------------------------------------------------------
  543. // TAbstractScriptableObject::ParentObject: 
  544. //
  545. // For now, nil means the null container.  In time, we should make a null container
  546. // that is based on TAbstractScriptableObject.
  547. //----------------------------------------------------------------------------------------
  548. TAbstractScriptableObject* TAbstractScriptableObject::ParentObject(const TAETransaction&)
  549.     {
  550.     return nil;
  551.     } // TAbstractScriptableObject::ParentObject 
  552.  
  553. //----------------------------------------------------------------------------------------
  554. // TAbstractScriptableObject::ElementIterator
  555. //----------------------------------------------------------------------------------------
  556. TAbstractObjectIterator* TAbstractScriptableObject::ElementIterator(const TAETransaction& t)
  557.     {
  558.     TAbstractObjectIterator* iter = nil;
  559.     
  560.     TAbstractScriptableObject* representative = this->RepresentativeScriptingObject(t);
  561.     if(representative != nil)
  562.         {
  563.         iter = representative->ElementIterator(t);
  564.         representative->DisposeDesignator();
  565.         }
  566.     
  567.     return iter;
  568.     } // TAbstractScriptableObject::ElementIterator
  569.  
  570. //----------------------------------------------------------------------------------------
  571. // TAbstractScriptableObject::CountElements: 
  572. //----------------------------------------------------------------------------------------
  573. long TAbstractScriptableObject::CountElements(const TAETransaction& t, DescType classToCount)
  574.     {
  575.     long count = 0;
  576.     
  577.     TAbstractObjectIterator* iter = this->ElementIterator(t);
  578.     if(iter != nil)
  579.         {
  580.         count = iter->CountElements(t, classToCount);
  581.         iter->Release();
  582.         }
  583.     
  584.     return count;
  585.     } // TAbstractScriptableObject::CountElements 
  586.  
  587. //----------------------------------------------------------------------------------------
  588. // TAbstractScriptableObject::AccessByIndex:
  589. //
  590. // Abstract method
  591. //----------------------------------------------------------------------------------------
  592. TAbstractScriptableObject* TAbstractScriptableObject::AccessByIndex(const TAETransaction& t, DescType desiredClass, long index)
  593.     {
  594.     TAbstractScriptableObject* result = nil;
  595.     
  596.     TAbstractObjectIterator* iter = this->ElementIterator(t);
  597.     if(iter != nil)
  598.         {
  599.         result = iter->GetIndexedElement(t, desiredClass, index);
  600.         iter->Release();
  601.         }
  602.     
  603.     return result;
  604.     } // TAbstractScriptableObject::AccessByIndex 
  605.  
  606. //----------------------------------------------------------------------------------------
  607. // TAbstractScriptableObject::AccessByName: 
  608. //
  609. // Abstract method
  610. //----------------------------------------------------------------------------------------
  611. TAbstractScriptableObject* TAbstractScriptableObject::AccessByName(const TAETransaction& t, DescType desiredClass, TDescriptor nameDesc)
  612.     {
  613.     TAbstractScriptableObject* result = nil;
  614.     
  615.     TAbstractObjectIterator* iter = this->ElementIterator(t);
  616.     if(iter != nil)
  617.         {
  618.         result = iter->GetNamedElement(t, desiredClass, nameDesc);        
  619.         iter->Release();
  620.         }
  621.     
  622.     return result;
  623.     }
  624.  
  625. //----------------------------------------------------------------------------------------
  626. // TAbstractScriptableObject::AccessByProperty: 
  627. //----------------------------------------------------------------------------------------
  628. TAbstractScriptableObject* TAbstractScriptableObject::AccessByProperty(const TAETransaction& t, DescType propertyIdentifier)
  629.     {
  630.     TAbstractScriptableObject* propertyObject = nil;
  631.     
  632.     switch(propertyIdentifier)
  633.         {        
  634.         //
  635.         // "contents of..." is the same as "every <<wildcard>> of..."
  636.         //
  637.         case pContents:
  638.             {
  639.             propertyObject = new TEveryItemProxy;
  640.             ((TEveryItemProxy*)propertyObject)->IEveryItemProxy(this, typeWildCard);
  641.             }
  642.             break;
  643.         
  644.         //
  645.         // "entire contents of..." is like "contents of...", but
  646.         // it includes items deep inside the child heirarchy of
  647.         // the specified container, whereas "contents of..." includes
  648.         // only the immediate children.
  649.         //
  650.         case pEntireContents:
  651.             {
  652.             propertyObject = new TEntireContents;
  653.             ((TEntireContents*)propertyObject)->IEntireContents(this);
  654.             }
  655.             break;
  656.         
  657.         //
  658.         // "properties of..." returns all of the properties of the
  659.         // specified object; multiple properties may be set as well.
  660.         //
  661.         case pProperties:
  662.             {
  663.             //
  664.             // The default type for the properties property is "typeWildCard," which indicates
  665.             // that the default type of each property should be returned.  Similarly, typeBest
  666.             // means return the best data type for each property, and typeNull means just return
  667.             // descriptions of the properties, and skip the actual data.  Any other data type
  668.             // can be requested; in that case, only the properties that can return that data
  669.             // type are provided.
  670.             //
  671.             // Of course, the data type returned for the properties property is _always_ typeAERecord.
  672.             //
  673.             propertyObject = new TGenericProperty;
  674.             ((TGenericProperty*)propertyObject)->IGenericProperty(this, TPropertyDataDescription(pProperties, 0, typeWildCard, typeBest));
  675.             }
  676.             break;
  677.         }
  678.     
  679.     //
  680.     // If we have not already created a property object, then
  681.     // look up this property name in our class data and generate
  682.     // a generic property token for it if it's found.
  683.     //
  684.     if(propertyObject == nil)
  685.         {
  686.         const TPropertyDescription* propertyDescription = this->DescriptionOfProperty(t, propertyIdentifier);
  687.         if((propertyDescription != nil) && (NeverCreateGenericProperty(propertyDescription->AdditionalInfo()) == false))
  688.             {
  689.             ASSERT(propertyDescription->PropertyIdentifier() == propertyIdentifier);
  690.             propertyObject = new TGenericProperty;
  691.             ((TGenericProperty*)propertyObject)->IGenericProperty(this, *propertyDescription);
  692.             }
  693.         else
  694.             {
  695.             TAbstractScriptableObject* representative = nil;
  696.             NOREGISTER(representative);
  697.             OSErr representativeError = noErr;
  698.             Try
  699.                 {
  700.                 representative = this->RepresentativeScriptingObject(t);
  701.                 if(representative != nil)
  702.                     propertyObject = representative->AccessByProperty(t, propertyIdentifier);
  703.                 }
  704.             Catch(representativeError)
  705.                 {
  706.                 }
  707.             if(representative != nil)
  708.                 representative->DisposeDesignator();
  709.             
  710.             if(propertyObject == nil)
  711.                 FailErr(errAENoSuchObject);
  712.             }
  713.         }
  714.     
  715.     return propertyObject;
  716.     } // TAbstractScriptableObject::AccessByProperty 
  717.  
  718. //----------------------------------------------------------------------------------------
  719. // TAbstractScriptableObject::Access: 
  720. //
  721. // The access method dispatches to the appropriate accessor (AccessByName, AccessByIndex,
  722. // AccessByProperty, etc.).  It also knows how to do formRelativePostion, formRange and
  723. // formOrdinal, provided that all of the token objects know about the property pContainer,
  724. // and the method 'ItemIndex' (AccessByProperty(pIndex)) is also supported.
  725. //----------------------------------------------------------------------------------------
  726. TAbstractScriptableObject* TAbstractScriptableObject::Access(const TAETransaction& t, DescType desiredClass, DescType keyForm, TDescriptor keyData )
  727.     {
  728.     TAbstractScriptableObject* resultToken = nil;
  729.     TDescriptor indexDescriptor;
  730.     TDescriptor indexDescriptor2;
  731.     OSErr err = noErr;
  732.     
  733.     switch( keyForm )
  734.         {
  735.         case formAbsolutePosition:
  736.             {
  737.             //
  738.             // formAbsolutePosition can contain either:
  739.             //        o    A positive integer (offset from beginning)
  740.             //        o    A negative integer (offset from end)
  741.             //        o    An ordinal (kAEFirst, kAEAny, etc.)
  742.             //
  743.             // Most of the ordinals (every one except kAEAll) are
  744.             // handled by the abstract base class TTokenObject.
  745.             // Similarly, negative indices are converted to an appropriate
  746.             // positive value by TTokenObject::AdjustNegativeIndex.
  747.             //
  748.             if(keyData.DescriptorType() == typeAbsoluteOrdinal)
  749.                 {
  750.                 DescType ordinal = keyData.GetDescTypeData(typeAbsoluteOrdinal);
  751.                 
  752.                 resultToken = this->AccessByOrdinal(t, desiredClass, ordinal);
  753.                 }
  754.             else
  755.                 {
  756.                 long index = keyData.GetSInt32Data();
  757.                 
  758.                 //
  759.                 // AdjustNegativeIndex just subracts the index from
  760.                 // one greater than the number of children in this object
  761.                 // (so an index of -1 specifies the last object, -2 specifies
  762.                 // the second to last object, and so on).
  763.                 //
  764.                 // Note:    There never seemed to be a need to override
  765.                 //            AdjustNegativeIndex, so I placed its implementation
  766.                 //            here and removed the virtual.
  767.                 //
  768.                 if(index < 0)
  769.                     index = this->CountElements(t, desiredClass) + 1 + index;
  770.             
  771.                 resultToken = this->AccessByIndex(t, desiredClass,index);
  772.                 }
  773.             }
  774.             break;
  775.         
  776.         case formUniqueID:
  777.             {
  778.             resultToken = this->AccessByUniqueID(t, desiredClass, keyData);
  779.             }
  780.             break;
  781.             
  782.         case formName:
  783.             {
  784.             resultToken = this->AccessByName(t, desiredClass,keyData);
  785.             }
  786.             break;
  787.         
  788.         case formPropertyID:
  789.             {
  790.             DescType propertyName = keyData.GetDescTypeData();
  791.             ASSERT(desiredClass == cProperty);
  792.             
  793.             resultToken = this->AccessByProperty(t, propertyName);
  794.             }
  795.             break;
  796.         
  797.         case formRelativePosition:
  798.             {
  799.             if(keyData.DescriptorType() != typeEnumeration)
  800.                 {
  801.                 FailErr(errAEEventNotHandled);
  802.                 }
  803.  
  804.             indexDescriptor = this->GetProperty(t, pIndex, typeLongInteger);
  805.             long indexNumber = indexDescriptor.GetSInt32Data();
  806.             DescType ordinal = keyData.GetDescTypeData(typeEnumeration);
  807.             TAbstractScriptableObject* parent = nil;
  808.             short delta;
  809.             
  810.             //
  811.             // We need a reference to our parent in
  812.             // order to access our siblings
  813.             //
  814.             parent = this->ParentObject(t);
  815.             if(parent == nil)
  816.                 FailErr(errAENoSuchObject);
  817.             long siblings = parent->CountElements(t);
  818.                     
  819.             //
  820.             // The ordinal can be one of:
  821.             //
  822.             //        o kAENext
  823.             //        o kAEPrevious
  824.             //
  825.             if((ordinal == kAENext) || (ordinal == kAEAfter))
  826.                 {
  827.                 delta = 1;
  828.                 indexNumber += delta;
  829.                 }
  830.             else if((ordinal == kAEPrevious) || (ordinal == kAEBefore))
  831.                 {
  832.                 delta = -1;
  833.                 indexNumber += delta;
  834.                 }
  835.             else if(ordinal == kAEBeginning)
  836.                 {
  837.                 delta = 1;
  838.                 indexNumber = 1;
  839.                 }
  840.             else if(ordinal == kAEEnd)
  841.                 {
  842.                 delta = -1;
  843.                 indexNumber = siblings;
  844.                 }
  845.             else
  846.                 {
  847.                 FailErr(errAEBadKeyForm);
  848.                 }
  849.             
  850.             //DebugPrintf("delta = %d", delta);
  851.             
  852.             //
  853.             // Advance the index number until we get to a
  854.             // token of the correct class
  855.             //
  856.             while((indexNumber > 0) && (indexNumber <= siblings))
  857.                 {                    
  858.                 //DebugPrintf("index now = %d", indexNumber);
  859.                 
  860.                 TAbstractScriptableObject* token = parent->AccessByIndex(t, typeWildCard, indexNumber);
  861.                 
  862.                 //DebugStr("\pGot an object");
  863.                 
  864.                 //
  865.                 // If the current token is of the correct type,
  866.                 // then add it into the resultToken.
  867.                 //
  868.                 if(token->DerivedFromOSLClass(t, desiredClass))
  869.                     {
  870.                     //DebugStr("\pIts type was good");
  871.                     
  872.                     resultToken = token;                    
  873.                     break;
  874.                     }
  875.                 //
  876.                 // If we don't accumulate the token, then
  877.                 // we must dispose of it
  878.                 //
  879.                 else
  880.                     {
  881.                     //DebugStr("\pWe did not want it");
  882.                     
  883.                     token->DisposeDesignator();
  884.                     token = nil;
  885.                     }
  886.                 
  887.                 //
  888.                 // Try the next one
  889.                 //
  890.                 indexNumber += delta;
  891.                 }
  892.             
  893.             //DebugStr("\pGetting rid of parent");
  894.             
  895.             parent->DisposeDesignator();
  896.             indexDescriptor.Dispose();
  897.             }
  898.             break;
  899.         
  900.         //
  901.         // An interesting thing about formRange:
  902.         //
  903.         // The script item 1 through item 2 of document 1 whose name contains "e"
  904.         // will compile down to items 1 through 2 of document 1 whose name contains "e",
  905.         // but will use formRange rather than using a whoseRange with the whose
  906.         // clause.  If you actually compile the script items 1 through 2 of document
  907.         // 1 whose name contains "e", on the other hand, the result LOOKS the same,
  908.         // but AppleScript will use a whoseRange in conjunction with the whose clause.
  909.         //
  910.         case formRange:
  911.             {
  912.             TDescriptor                        clonedKeyData;
  913.             TDescriptor                        rangeStop;
  914.             TDescriptor                        rangeStart;
  915.             TDescriptor                        startContainer;
  916.             TDescriptor                        stopContainer;
  917.             TTokenDescriptor                startTokenDesc;
  918.             TTokenDescriptor                stopTokenDesc;
  919.             TAbstractScriptableObject*        startToken = nil;
  920.             TAbstractScriptableObject*        stopToken = nil;
  921.             DescType                        tempDesiredClass;
  922.             DescType                        tempKeyForm;
  923.             TDescriptor                        tempKeyData;
  924.             
  925.             Try
  926.                 {
  927.                 //
  928.                 // Get the rangeStart and rangeStop parameters; make sure
  929.                 // they are returned as AERecords.
  930.                 //
  931.                 clonedKeyData = keyData.Coerce(typeAERecord);
  932.                 rangeStart = clonedKeyData.GetDescriptorParameter(keyAERangeStart);
  933.                 rangeStop  = clonedKeyData.GetDescriptorParameter(keyAERangeStop);
  934.  
  935.                 //
  936.                 // At this point, rangeStart is a special object specifier
  937.                 // of the form "item N of «token we previously generated»"
  938.                 // (assuming the original expression was "item N through
  939.                 // item M of document 1 whose name contains "e""); however,
  940.                 // the range stop descriptor will be of the form
  941.                 // "item M of document 1".  This is QUITE incorrect, as
  942.                 // item M of document 1 may not have an e in its name,
  943.                 // and it almost certainly is not the Mth item with an
  944.                 // e (unless the first M items all have e's).  Therefore,
  945.                 // we may recursively call Resolve to determine the start
  946.                 // token, but we need to do more work to find the stop token.
  947.                 //
  948.                 // Even though we could just call "resolve" on the rangeStart
  949.                 // token, we won't bother to do that just for the sake
  950.                 // of consistancy.
  951.                 //
  952.                 rangeStart.GetObjectSpecifierParameters(tempDesiredClass, tempKeyForm, &tempKeyData);
  953.                 startToken = this->Access(t, tempDesiredClass, tempKeyForm, tempKeyData);
  954.                 tempKeyData.Dispose();
  955.  
  956.                 //
  957.                 // Do the same resolution on the range stop (in this
  958.                 // instance, calling resolve is NOT an option)
  959.                 //
  960.                 rangeStop.GetObjectSpecifierParameters(tempDesiredClass, tempKeyForm, &tempKeyData);
  961.                 stopToken = this->Access(t, tempDesiredClass, tempKeyForm, tempKeyData);
  962.                 tempKeyData.Dispose();
  963.                 
  964.                 //
  965.                 // Note that at this point, "this" is not necessarily
  966.                 // the parent of the start and stop token; it may, for
  967.                 // example, be the collection that resulted from evaluating
  968.                 // a whose clause (as in the above example).  Regardless,
  969.                 // the start and stop tokens will always be elements
  970.                 // of "this."
  971.                 //
  972.                 Boolean adding = false;
  973.                 Boolean willStopAdding = false;
  974.                 TAbstractObjectIterator* iter = this->ElementIterator(t);
  975.                 for(iter->Reset(t); iter->More(t); iter->Next(t))
  976.                     {
  977.                     TAbstractScriptableObject* token = iter->Current(t);
  978.                     Boolean isStart = startToken->ObjectsAreTheSame(t, token);
  979.                     Boolean isStop = stopToken->ObjectsAreTheSame(t, token);
  980.                     if(isStart || isStop)
  981.                         {
  982.                         if((adding == true) || ((isStart) && (isStop)))
  983.                             willStopAdding = true;
  984.                         adding = true;
  985.                         }
  986.                         
  987.                     if((adding) && (token->DerivedFromOSLClass(t, desiredClass)))
  988.                         token->AddThisToMarkToken(resultToken, kSingleItemOrUnion);
  989.                     else
  990.                         token->DisposeDesignator();
  991.                     if(willStopAdding)
  992.                         adding = false;
  993.                     }
  994.                 }
  995.             Catch(err)
  996.                 {
  997.                 //
  998.                 // ◊Script:  Need to catch and propagate this error
  999.                 //
  1000.                 //DebugPrintf("Drat, formRange failed somewhere (err = %d)", Except_Error());
  1001.                 }
  1002.             
  1003.             clonedKeyData.Dispose();
  1004.             rangeStart.Dispose();
  1005.             rangeStop.Dispose();
  1006.             indexDescriptor.Dispose();
  1007.             indexDescriptor2.Dispose();
  1008.             startContainer.Dispose();
  1009.             stopContainer.Dispose();
  1010.             startTokenDesc.Dispose(); 
  1011.             stopTokenDesc.Dispose();
  1012.             tempKeyData.Dispose();
  1013.             }
  1014.             break;
  1015.  
  1016.         case formWhose:
  1017.             {
  1018.             TDescriptor scopeOfSearch;
  1019.             
  1020.             TAbstractSearchSpec* searchSpec = this->ParseWhoseDescriptor(keyData, scopeOfSearch);
  1021.             REQUIREVALIDPOINTER(searchSpec);
  1022.             TObjectCollector collector(scopeOfSearch);
  1023.             this->AccessBySearchSpec(t, &collector, desiredClass, searchSpec);
  1024.         
  1025.             //
  1026.             // In some cases, the element iterator returned by the root
  1027.             // object will run asynchronously.  If it does, it will
  1028.             // attach a behavior to the collector that will allow us to
  1029.             // wait until the async code completes.
  1030.             //
  1031.             collector.CollectorRequest(t, kWaitForAsyncSearchesToComplete);
  1032.             resultToken = collector.CollectionResult();
  1033.             scopeOfSearch.Dispose();
  1034.             }
  1035.             break;
  1036.  
  1037.         default:
  1038.             {
  1039.             FailErr(errAEBadKeyForm);
  1040.             }
  1041.         }
  1042.  
  1043.     return resultToken;
  1044.     }
  1045.  
  1046. //----------------------------------------------------------------------------------------
  1047. // TAbstractScriptableObject::AccessByUniqueID: 
  1048. //----------------------------------------------------------------------------------------
  1049. TAbstractScriptableObject* TAbstractScriptableObject::AccessByUniqueID(const TAETransaction& t, DescType desiredClass, TDescriptor uniqueID)
  1050.     {
  1051.     TAbstractScriptableObject* result = nil;
  1052.     
  1053.     TAbstractScriptableObject* representative = nil;
  1054.     NOREGISTER(representative);
  1055.     OSErr representativeError = noErr;
  1056.     Try
  1057.         {
  1058.         representative = this->RepresentativeScriptingObject(t);
  1059.         if(representative != nil)
  1060.             result = representative->AccessByUniqueID(t, desiredClass, uniqueID);
  1061.         }
  1062.     Catch(representativeError)
  1063.         {
  1064.         }
  1065.     if(representative != nil)
  1066.         representative->DisposeDesignator();
  1067.     FailErr(representativeError);
  1068.  
  1069.     if(result == nil)
  1070.         FailErr(errAEEventNotHandled);
  1071.     
  1072.     return result;
  1073.     } // TAbstractScriptableObject::AccessByUniqueID 
  1074.  
  1075. //----------------------------------------------------------------------------------------
  1076. // TAbstractScriptableObject::AccessByOrdinal:
  1077. //
  1078. // This method automatically handles kAEFirst, kAELast, kAEMiddle, kAEAny & kAEAll.
  1079. // All that the derived classes need to do is provide 'CountElements' and 'AccessByIndex'
  1080. // methods.
  1081. //----------------------------------------------------------------------------------------
  1082. TAbstractScriptableObject* TAbstractScriptableObject::AccessByOrdinal(const TAETransaction& t, DescType desiredClass, DescType ordinal)
  1083.     {
  1084.     TAbstractScriptableObject* resultToken;
  1085.     
  1086.     switch( ordinal )
  1087.         {
  1088.         case kAEFirst:
  1089.             {
  1090.             resultToken = this->AccessByIndex(t, desiredClass,1);
  1091.             break;
  1092.             }
  1093.         
  1094.         case kAELast:
  1095.             {
  1096.             resultToken = this->AccessByIndex(t, desiredClass,this->CountElements(t, desiredClass));
  1097.             break;
  1098.             }
  1099.         
  1100.         case kAEMiddle:
  1101.             {
  1102.             resultToken = this->AccessByIndex(t, desiredClass,(this->CountElements(t, desiredClass) + 1) >> 1);
  1103.             break;
  1104.             }
  1105.         
  1106.         case kAEAny:
  1107.             {
  1108.             long totalNumber = this->CountElements(t, desiredClass);    
  1109.             resultToken = this->AccessByIndex(t, desiredClass, PseudoRandomFromMToN(1, totalNumber));
  1110.             break;
  1111.             }
  1112.     
  1113.         case kAEAll:
  1114.             {
  1115.             //
  1116.             // AppleScript sends "properties of ..." as want class cProperty
  1117.             // formAbsoluteOrdinal (kAEAll) from..., so we have special
  1118.             // checking for cProperty here.
  1119.             //
  1120.             if(desiredClass == cProperty)
  1121.                 {
  1122.                 resultToken = new TGenericProperty;
  1123.                 ((TGenericProperty*)resultToken)->IGenericProperty(this, TPropertyDataDescription(pProperties, 0, typeWildCard, typeBest));
  1124.                 }
  1125.             else
  1126.                 {
  1127.                 TEveryItemProxy* everyItem = new TEveryItemProxy;
  1128.                 everyItem->IEveryItemProxy(this, desiredClass);
  1129.                 resultToken = everyItem;
  1130.                 }
  1131.             }
  1132.             break;
  1133.  
  1134.         default:
  1135.             {
  1136.             ASSERT(false);
  1137.             FailErr(errAEEventNotHandled);
  1138.             break;
  1139.             }
  1140.         }
  1141.  
  1142.     return resultToken;
  1143.     } // TAbstractScriptableObject::AccessByOrdinal 
  1144.  
  1145. //----------------------------------------------------------------------------------------
  1146. // TAbstractScriptableObject::AccessBySearchSpec: 
  1147. //----------------------------------------------------------------------------------------
  1148. void TAbstractScriptableObject::AccessBySearchSpec(const TAETransaction& t, TAbstractCollector* collector, DescType desiredClass, TAbstractSearchSpec* searchSpec)
  1149.     {
  1150.     //
  1151.     // First, do an entire search, acumulating all results
  1152.     // 
  1153.     TAbstractObjectIterator* iter = this->ElementIterator(t);
  1154.     if(iter) 
  1155.         {
  1156.         iter->AccessBySearchSpec(t, collector, desiredClass, searchSpec);
  1157.         iter->Release();
  1158.         }
  1159.     } // TAbstractScriptableObject::AccessBySearchSpec
  1160.  
  1161. //----------------------------------------------------------------------------------------
  1162. // TAbstractScriptableObject::BestType: 
  1163. //
  1164. // This method returns the best data type for the token (the one that best represents
  1165. // most of the information stored in the object).  The assumption is that the best type
  1166. // is the default data type of the object, but this will not necessarily be the case
  1167. // for all token classes.
  1168. //
  1169. // RULE:  The best type should be the data type that has the highest data fidelity
  1170. // for your object.  For most objects, it should be possible to request the best
  1171. // type from get data and then coerce the result to any other data type that the
  1172. // object can return (except typeObjectSpecifier).
  1173. //
  1174. // RULE:  The best type should be the data type that you want to be used when doing
  1175. // data comparisons when resolving whose clauses
  1176. //
  1177. // RULE:  If you expect to EVER be passed an object of typeObjectSpecifier to your
  1178. // object's set data routine, then your best type MUST be typeObjectSpecifier!  If
  1179. // it isn't, then the scripting code will always attempt to resolve the object
  1180. // specifier and get your property's best data type from the resulting object.
  1181. //
  1182. // RULE:  If your object EVER returns an enumeration whose value is the same as
  1183. // any four-character-code that is defined as a property in ANY terminology
  1184. // resource (e.g. pName), then your best type MUST be typeEnumeration!
  1185. // AppleScript will ALWAYS compile your enumeration as an object specifier rather
  1186. // than an enumeration if it can find a property with the same four-character code
  1187. // as your enumeration; the scripting code will automatically translate it back
  1188. // into an enumeration for you before passing it to your set data routine, but
  1189. // ONLY if your best type is typeEnumeration!  Note also that if your enumerations
  1190. // have the same four-character-code as a property that can return an enumeration
  1191. // usable by your property (circular dependency), then the scripting code will
  1192. // not be able to interpret some scripts correctly.
  1193. //----------------------------------------------------------------------------------------
  1194. DescType TAbstractScriptableObject::BestType(const TAETransaction& t, DescType propertyName)
  1195.     {
  1196.     DescType bestType = 0;
  1197.     
  1198.     const TPropertyDescription* propertyData = this->DescriptionOfProperty(t, propertyName);
  1199.     if(propertyData != nil)
  1200.         bestType = propertyData->BestType();
  1201.     
  1202.     if((bestType == 0) || (BestTypeIsSameAsDefaultType(propertyData->AdditionalInfo())))
  1203.         bestType = this->DefaultType(t, propertyName);
  1204.     
  1205.     return bestType;
  1206.     } // TAbstractScriptableObject::BestType 
  1207.  
  1208. //----------------------------------------------------------------------------------------
  1209. // TAbstractScriptableObject::DefaultType:
  1210. //
  1211. // This method returns the data type that is returned by the token if no specific type
  1212. // is requested.  The default default type is typeObjectSpecifier, because all tokens
  1213. // are expected to be able to build object specifiers for themselves; any token whose
  1214. // default type is not typeObjectSpecifier should override this method (of course).
  1215. //
  1216. // RULE:  The default type of your object should always be the most convenient type
  1217. // for the user (scriptor) to work with when writing simple scripts in the script
  1218. // editor.
  1219. //----------------------------------------------------------------------------------------
  1220. DescType TAbstractScriptableObject::DefaultType(const TAETransaction& t, DescType propertyName)
  1221.     {
  1222.     DescType defaultType = 0;
  1223.     
  1224.     const TPropertyDescription* propertyData = this->DescriptionOfProperty(t, propertyName);
  1225.     if(propertyData != nil)
  1226.         defaultType = propertyData->DefaultType();
  1227.     
  1228.     if(defaultType == 0)
  1229.         defaultType = typeObjectSpecifier;
  1230.     
  1231.     return defaultType;
  1232.     } // TAbstractScriptableObject::DefaultType 
  1233.  
  1234. //----------------------------------------------------------------------------------------
  1235. // TAbstractScriptableObject::CanReturnDataOfType:
  1236. //
  1237. // Every token should override this class and return 'true' if it can return a specified
  1238. // data type, or call 'inherited' if it does not recognize it.  All tokens are expected
  1239. // to know how to make object specifiers for themselves and handle requests for 'typeBest'
  1240. // and 'typeWildCard'.  A token class does not need to override this method if the only
  1241. // data types it can return are its default type, its best type and typeObjectSpecifier.
  1242. //----------------------------------------------------------------------------------------
  1243. Boolean TAbstractScriptableObject::CanReturnDataOfType(const TAETransaction& t, DescType propertyName, DescType desiredType)
  1244.     {
  1245.     return (    (desiredType == typeObjectSpecifier)                ||
  1246.                 (desiredType == typeAEList)                            ||
  1247.                 (desiredType == this->BestType(t, propertyName))    ||
  1248.                 (desiredType == this->DefaultType(t, propertyName))        );
  1249.     } // TAbstractScriptableObject::CanReturnDataOfType 
  1250.  
  1251. //----------------------------------------------------------------------------------------
  1252. // TAbstractScriptableObject::DetermineDataTypeToReturn:
  1253. //
  1254. // A token object should call this method from its GetData method; if the token object
  1255. // also overrides 'CanReturnDataOfType', then the return value of this method will be the
  1256. // data type that the token can generate that the caller most wanted to see. If there is
  1257. // no match between what the caller wants and what can be provided, then this
  1258. // method will fail with errAECantSupplyType.
  1259. //
  1260. // Also, 'requestedTypes' may be an empty list or a null descriptor; if it is either,
  1261. // this function will return 'this->DefaultType()'
  1262. //----------------------------------------------------------------------------------------
  1263. DescType TAbstractScriptableObject::DetermineDataTypeToReturn(const TAETransaction& t, DescType propertyName, TDescriptor requestedTypes)
  1264.     {
  1265.     DescType typeToReturn = 0;
  1266.     
  1267.     //
  1268.     // 'CountItems' is smart; it will return '0' for a null descriptor
  1269.     // as well as an empty list.  It will return '1' for a descriptor
  1270.     // that is not an AEList.  Our descriptor iterator can also iterate over
  1271.     // a single-item TDescriptor.
  1272.     //
  1273.     // The point of this check is:  if there was no list of requested types,
  1274.     // or if the list of requested types is empty, then the type to
  1275.     // return is the object's default type
  1276.     //
  1277.     if(requestedTypes.CountItems() == 0)
  1278.         {
  1279.         typeToReturn = this->DefaultType(t, propertyName);
  1280.         }
  1281.     //
  1282.     // If there is a list of requested types, then we must iterate over
  1283.     // them to decide which type to return
  1284.     //
  1285.     else
  1286.         {
  1287.         for(TDescriptorIterator iter(requestedTypes); iter.More(); iter.Next())
  1288.             {
  1289.             DescType anAcceptableType = iter.GetCurrentDescTypeData();
  1290.                         
  1291.             //
  1292.             // Every object has a best type, so we always
  1293.             // accept 'typeBest'
  1294.             //
  1295.             if(anAcceptableType == typeBest)
  1296.                 {
  1297.                 typeToReturn = this->BestType(t, propertyName);
  1298.                 break;
  1299.                 }            
  1300.             
  1301.             //
  1302.             // If the requested type is 'any type at all',
  1303.             // then return the default type
  1304.             //
  1305.             if(anAcceptableType == typeWildCard)
  1306.                 {
  1307.                 typeToReturn = this->DefaultType(t, propertyName);
  1308.                 break;
  1309.                 }            
  1310.             
  1311.             //
  1312.             // If a specific type is requested, return it
  1313.             // if and only if this object can generate
  1314.             // said type.
  1315.             //
  1316.             if(this->CanReturnDataOfType(t, propertyName, anAcceptableType))
  1317.                 {
  1318.                 typeToReturn = anAcceptableType;
  1319.                 break;
  1320.                 }
  1321.             }
  1322.         }
  1323.                 
  1324.     //
  1325.     // If we can't return any of the requested types, then spew
  1326.     //
  1327.     if(typeToReturn == 0)
  1328.         {
  1329.         FailErr(errAECantSupplyType);
  1330.         }
  1331.  
  1332.     return typeToReturn;
  1333.     } // TAbstractScriptableObject::DetermineDataTypeToReturn 
  1334.  
  1335. //----------------------------------------------------------------------------------------
  1336. // TAbstractScriptableObject::PropertyExists
  1337. //----------------------------------------------------------------------------------------
  1338. Boolean TAbstractScriptableObject::PropertyExists(const TAETransaction& t, DescType propertyName)
  1339.     {
  1340.     const TPropertyDescription* propertyDescription = this->DescriptionOfProperty(t, propertyName);
  1341.     
  1342.     return propertyDescription != nil;
  1343.     } // TAbstractScriptableObject::PropertyExists
  1344.     
  1345. //----------------------------------------------------------------------------------------
  1346. // TAbstractScriptableObject::DescriptionOfProperty
  1347. //----------------------------------------------------------------------------------------
  1348. const TPropertyDescription* TAbstractScriptableObject::DescriptionOfProperty(const TAETransaction& t, DescType propertyName)
  1349.     {
  1350.     TAbstractScriptableObject* representative = this->RepresentativeScriptingObject(t);
  1351.     const TClassData* classData = this->ClassData();
  1352.     const TPropertyDescription* propertyDescription = nil;
  1353.     
  1354.     while(classData != nil)
  1355.         {
  1356.         const TClassPropertyInfo& propertyInfo = classData->ClassPropertyInfo();
  1357.         propertyDescription = propertyInfo.DescriptionOfProperty(propertyName);
  1358.  
  1359.         if (propertyDescription != nil)
  1360.             classData = nil;
  1361.         else
  1362.             {
  1363.             if(representative != nil)
  1364.                 {
  1365.                 classData = representative->ClassData();
  1366.                 representative->DisposeDesignator();
  1367.                 representative = nil;
  1368.                 }
  1369.             else
  1370.                 classData = classData->SuperClass();
  1371.             }
  1372.         }
  1373.             
  1374.     return propertyDescription;
  1375.     } // TAbstractScriptableObject::DescriptionOfProperty
  1376.     
  1377. //----------------------------------------------------------------------------------------
  1378. // TAbstractScriptableObject::NumberOfProperties
  1379. //----------------------------------------------------------------------------------------
  1380. long TAbstractScriptableObject::NumberOfProperties(const TAETransaction& t)
  1381.     {
  1382.     TAbstractScriptableObject* representative = this->RepresentativeScriptingObject(t);
  1383.     const TClassData* classData = this->ClassData();
  1384.     long propertyCount = 0;
  1385.     
  1386.     while(classData != nil)
  1387.         {
  1388.         const TClassPropertyInfo& propertyInfo = classData->ClassPropertyInfo();
  1389.         propertyCount += propertyInfo.NumberOfProperties();
  1390.  
  1391.         if(representative != nil)
  1392.             {
  1393.             classData = representative->ClassData();
  1394.             representative->DisposeDesignator();
  1395.             representative = nil;
  1396.             }
  1397.         else
  1398.             classData = classData->SuperClass();
  1399.         }
  1400.     
  1401.     return propertyCount;
  1402.     } // TAbstractScriptableObject::NumberOfProperties
  1403.     
  1404. //----------------------------------------------------------------------------------------
  1405. // TAbstractScriptableObject::DescriptionOfNthProperty
  1406. //
  1407. // Normally I would have the range be from 0 to N-1, but to be consistant with the
  1408. // rest of the scripting code I choose to make the range 1 to N instead.
  1409. //----------------------------------------------------------------------------------------
  1410. const TPropertyDescription* TAbstractScriptableObject::DescriptionOfNthProperty(const TAETransaction& t, long propertyNumber)
  1411.     {
  1412.     TAbstractScriptableObject* representative = this->RepresentativeScriptingObject(t);
  1413.     const TClassData* classData = this->ClassData();
  1414.     const TPropertyDescription* propertyDescription = nil;
  1415.     
  1416.     //
  1417.     // Adjust the property number so that it will be 0-based
  1418.     // rather than 1-based once we get into the loop.
  1419.     //
  1420.     --propertyNumber;
  1421.     
  1422.     while(classData != nil)
  1423.         {
  1424.         const TClassPropertyInfo& propertyInfo = classData->ClassPropertyInfo();
  1425.         long numberOfPropertiesForThisClass = propertyInfo.NumberOfProperties();
  1426.         if(propertyNumber < numberOfPropertiesForThisClass)
  1427.             propertyDescription = propertyInfo.DescriptionOfNthProperty(propertyNumber);
  1428.         else
  1429.             propertyNumber -= numberOfPropertiesForThisClass;
  1430.  
  1431.         if(representative != nil)
  1432.             {
  1433.             classData = representative->ClassData();
  1434.             representative->DisposeDesignator();
  1435.             representative = nil;
  1436.             }
  1437.         else
  1438.             classData = classData->SuperClass();
  1439.         
  1440.         if (propertyDescription != nil)
  1441.             classData = nil;
  1442.         }
  1443.     
  1444.     return propertyDescription;
  1445.     } // TAbstractScriptableObject::DescriptionOfNthProperty
  1446.  
  1447. //----------------------------------------------------------------------------------------
  1448. // TAbstractScriptableObject::GetDataGivenListOfTypes: 
  1449. //
  1450. // This is the GetData method called by the Get Data event.  It determines which
  1451. // type should actually be returned, and then calls the simpler version of GetData, above.
  1452. //
  1453. // New feature:  if GetData(DescType requestedType) may now return a descriptor that
  1454. // is some type other than 'requestedType'; if this happens, then this version of
  1455. // GetData will attempt to coerce the supplied type into the requested type.
  1456. //
  1457. // Formerly, this routine was called 'GetData', but the xLC compiler had trouble
  1458. // with the polymorphism, so it was renamed.
  1459. //----------------------------------------------------------------------------------------
  1460. TDescriptor TAbstractScriptableObject::GetDataGivenListOfTypes(const TAETransaction& t, DescType propertyName, TDescriptor listOfRequestedTypes, unsigned long additionalInfo /*=kLookupAdditionalInfo*/)
  1461.     {
  1462.     TDescriptor result;
  1463.     
  1464.     //
  1465.     // Find a type that we can return from the list of types that
  1466.     // the client said were acceptable.  Remember which type we decided
  1467.     // was best; we'll try to coerce to it if the token returns some
  1468.     // other type.
  1469.     //
  1470.     DescType requestedType = this->DetermineDataTypeToReturn(t, propertyName, listOfRequestedTypes);
  1471.     DescType coerceToType = requestedType;
  1472.     
  1473.     //
  1474.     // If the requested type is 'typeList', then what we really want to
  1475.     // return is a list of the default type of this object.  Note that
  1476.     // some objects (mostly proxies, such as the selection) have a default
  1477.     // type of typeList; if this is the case, then we want to return a
  1478.     // list of the best type of the object.
  1479.     //
  1480.     if(requestedType == typeAEList)
  1481.         requestedType = this->DefaultType(t, propertyName);
  1482.     if(requestedType == typeAEList)
  1483.         requestedType = this->BestType(t, propertyName);
  1484.     
  1485.     //
  1486.     // Go ahead and ask for the data now that we've figured out
  1487.     // what sort of type we'd like to see.
  1488.     //
  1489.     result = this->GetDataOfType(t, propertyName, requestedType, additionalInfo);
  1490.  
  1491.     //
  1492.     // We need to try to coerce again, even though GetDataOfType
  1493.     // has already tried.  The reason is we may change the requested
  1494.     // type from typeAEList to some other type; if that's
  1495.     // the case, and we don't get a list back, then we need to
  1496.     // coerce the result into a list.
  1497.     //
  1498.     this->CoerceResultToRequestedType(result, coerceToType);
  1499.     
  1500.     return result;
  1501.     } // TAbstractScriptableObject::GetDataGivenListOfTypes 
  1502.     
  1503. //----------------------------------------------------------------------------------------
  1504. // TAbstractScriptableObject::GetDataOfType: 
  1505. //
  1506. // GetDataOfType calls GetData, and if the data type does not match exactly it
  1507. // does a type coercion, if possible.
  1508. //----------------------------------------------------------------------------------------
  1509. TDescriptor TAbstractScriptableObject::GetDataOfType(const TAETransaction& t, DescType propertyName, DescType requestedType, unsigned long additionalInfo /*=kLookupAdditionalInfo*/)
  1510.     {
  1511.     TDescriptor result;
  1512.     
  1513.     if(additionalInfo == kLookupAdditionalInfo)
  1514.         {
  1515.         const TPropertyDescription* propDescription = this->DescriptionOfProperty(t, propertyName);
  1516.         additionalInfo = propDescription == nil ? 0 : propDescription->AdditionalInfo();
  1517.         }
  1518.         
  1519.     //
  1520.     // If the requested type is 'typeObjectSpecifier', then build an object
  1521.     // specifier for this object _unless_ the best type of this object is
  1522.     // typeObjectSpecifier.  Specifying a best type of typeObjectSpecifier
  1523.     // usually indicates that this object is a proxy for other objects (e.g.
  1524.     // the selection, which returns a list of selected items in response to
  1525.     // a get data event.)
  1526.     //
  1527.     // The reason we bifurcate here rather than allowing TAbstractScriptableObject::GetData
  1528.     // to handle the request for typeObjectSpecifier is that we would like
  1529.     // to allow objects (particularly properties) the option of always returning
  1530.     // their best data type, and allowing this routine to do a coercion if
  1531.     // the requested type was something other than its best type.  If the object
  1532.     // had to test for typeObjectSpecifier and call inherited, the benefit of
  1533.     // being able to always return the same data type is largely lost.
  1534.     //
  1535.     if((requestedType == typeObjectSpecifier) && (this->BestType(t, propertyName) != typeObjectSpecifier))
  1536.         result = this->BuildObjectSpecifierForProperty(t, propertyName);
  1537.     else
  1538.         {
  1539.         result = this->GetProperty(t, propertyName, requestedType, additionalInfo);
  1540.         this->CoerceResultToRequestedType(result, requestedType);
  1541.         }
  1542.         
  1543.     return result;
  1544.     } // TAbstractScriptableObject::GetDataOfType
  1545.  
  1546. //----------------------------------------------------------------------------------------
  1547. // TAbstractScriptableObject::CoerceResultToRequestedType
  1548. //
  1549. // This is a method of TAbstractScriptableObject rather than TDescriptor because
  1550. // I thought perhaps that the best type of the object that this data came from
  1551. // might sometimes play a part in deciding how to coerce
  1552. //----------------------------------------------------------------------------------------
  1553. void TAbstractScriptableObject::CoerceResultToRequestedType(TDescriptor& result, DescType requestedType)
  1554.     {
  1555.     DescType returnedType = result.DescriptorType();
  1556.     
  1557.     //
  1558.     // Was the returned type different from the requested type?
  1559.     //
  1560.     if((returnedType != requestedType) && (requestedType != typeWildCard) && (requestedType != typeBest))
  1561.         {
  1562.         //
  1563.         // Before coercing, test for some situations that are okay
  1564.         //
  1565.         //        1.    If the requested type was typeLongInteger, but the result is
  1566.         //            typeSInt64, then assume that the data was promoted to an SInt64
  1567.         //            because it would not fit into a long integer
  1568.         //
  1569.         //        2.    If the returned type is typeAEList, assume that multiple items
  1570.         //            were returned (e.g. get selection), even if some other type
  1571.         //            was requested
  1572.         //
  1573.         //        3.    Similarly, typeAERecord is okay (pProperties)
  1574.         //
  1575.         //        4.    Also, typeNull is okay (can't be coerced--just let it go through).
  1576.         //            The caller should have failed if the data weren't available.
  1577.         //
  1578.         // Note the negation in the 'if'; we do the coercion unless one of these
  1579.         // exceptions are true.  (I thought it was easier to read this way...)
  1580.         //
  1581.         if(    !(    ((requestedType == typeLongInteger) && (returnedType == typeSInt64))    ||
  1582.                 (returnedType == typeAEList)                                            ||
  1583.                 (returnedType == typeAERecord)                                            ||
  1584.                 (returnedType == typeNull) )                                            )
  1585.             {
  1586.             //
  1587.             // Try to coerce... if coercion fails, then dispose the result
  1588.             // and resignal the failure
  1589.             //
  1590.             OSErr err = result.AttemptCoerceInPlace(requestedType);
  1591.             if(err != noErr)
  1592.                 {
  1593.                 result.Dispose();
  1594.                 FailErr(err);
  1595.                 }
  1596.             }
  1597.         }
  1598.     } // TAbstractScriptableObject::CoerceResultToRequestedType
  1599.  
  1600. #if 0
  1601.  
  1602. //----------------------------------------------------------------------------------------
  1603. // TAbstractScriptableObject::GetData: 
  1604. //
  1605. // GetData treats the requested type as being purely advisory.  Call 'GetDataOfType'
  1606. // to insure that the correct data type is returned if an exact match is required.
  1607. //----------------------------------------------------------------------------------------
  1608. TDescriptor TAbstractScriptableObject::GetData(const TAETransaction& t, DescType requestedType)
  1609.     {
  1610.     return this->GetProperty(t, pContents, desiredType);
  1611.     } // TAbstractScriptableObject::GetData 
  1612.  
  1613. #endif
  1614.  
  1615. //----------------------------------------------------------------------------------------
  1616. // TAbstractScriptableObject::GetDataSizeGivenListOfTypes: 
  1617. //----------------------------------------------------------------------------------------
  1618. long TAbstractScriptableObject::GetDataSizeGivenListOfTypes(const TAETransaction& t, DescType propertyName, TDescriptor listOfRequestedTypes)
  1619.     {
  1620.     long theSize = 0;
  1621.     OSErr err = noErr;
  1622.     
  1623.     //
  1624.     // Find a type that we can return from the list of types that
  1625.     // the client said were acceptable
  1626.     //
  1627.     DescType requestedType = this->DetermineDataTypeToReturn(t, propertyName, listOfRequestedTypes);
  1628.     
  1629.     Try
  1630.         {
  1631.         theSize = this->GetDataSize(t, propertyName, requestedType);
  1632.         }
  1633.     Catch(err)
  1634.         {
  1635.         TDescriptor data;
  1636.         
  1637.         data = this->GetDataGivenListOfTypes(t, propertyName, listOfRequestedTypes);
  1638.         if(data.DescriptorType() != typeNull)
  1639.             {
  1640.             theSize = data.DataSize();
  1641.             }
  1642.         data.Dispose();
  1643.         }
  1644.     
  1645.     return theSize;
  1646.     } // TAbstractScriptableObject::GetDataSizeGivenListOfTypes 
  1647.  
  1648. //----------------------------------------------------------------------------------------
  1649. // TAbstractScriptableObject::GetDataSize:
  1650. //
  1651. // Derived classes may override this method to optimize 'GetDataSizeGivenListOfTypes',
  1652. // above.  If 'GetDataSize' is not overridden, then the base class implementation
  1653. // (this method) will fail, and GetDataSizeGivenListOfTypes will use GetData to determine
  1654. // how large the data is.
  1655. //----------------------------------------------------------------------------------------
  1656. long TAbstractScriptableObject::GetDataSize(const TAETransaction&, DescType /*propertyName*/, DescType /*requestedType*/)
  1657.     {
  1658.     FailErr(errAEEventNotHandled);
  1659.     return 0;
  1660.     } // TAbstractScriptableObject::GetDataSize 
  1661.  
  1662. //----------------------------------------------------------------------------------------
  1663. // TAbstractScriptableObject::SetData:
  1664. //
  1665. // Tokens that are not modifiable do not override SetData.
  1666. //----------------------------------------------------------------------------------------
  1667. void TAbstractScriptableObject::SetData(const TAETransaction& t, TDescriptor keyData)
  1668.     {
  1669.     this->SetProperty(t, pContents, keyData);
  1670.     } // TAbstractScriptableObject::SetData 
  1671.  
  1672. //----------------------------------------------------------------------------------------
  1673. // TAbstractScriptableObject::GetProperty
  1674. //----------------------------------------------------------------------------------------
  1675. TDescriptor TAbstractScriptableObject::GetProperty(const TAETransaction& t, DescType propertyName, DescType desiredType)
  1676.     {
  1677.     const TPropertyDescription* propDescription = this->DescriptionOfProperty(t, propertyName);
  1678.     
  1679.     return this->GetProperty(t, propertyName, desiredType, propDescription == nil ? 0 : propDescription->AdditionalInfo());
  1680.     } // TAbstractScriptableObject::GetProperty
  1681.     
  1682. //----------------------------------------------------------------------------------------
  1683. // TAbstractScriptableObject::SetProperty
  1684. //----------------------------------------------------------------------------------------
  1685. void TAbstractScriptableObject::SetProperty(const TAETransaction& t, DescType propertyName, TDescriptor& data)
  1686.     {
  1687.     const TPropertyDescription* propDescription = this->DescriptionOfProperty(t, propertyName);
  1688.     
  1689.     this->SetProperty(t, propertyName, data, propDescription == nil ? 0 : propDescription->AdditionalInfo());
  1690.     } // TAbstractScriptableObject::SetProperty
  1691.  
  1692. //----------------------------------------------------------------------------------------
  1693. // TAbstractScriptableObject::GetProperty: 
  1694. //----------------------------------------------------------------------------------------
  1695. TDescriptor TAbstractScriptableObject::GetProperty(const TAETransaction& t, DescType propertyIdentifer, DescType desiredType, unsigned long additionalInfo)
  1696.     {
  1697.     TDescriptor data;
  1698.     
  1699.     switch(propertyIdentifer)
  1700.         {
  1701.         case pClass:
  1702.             {
  1703.             data.SetDescTypeData(this->ObjectClass(t));
  1704.             }
  1705.             break;
  1706.         
  1707.         case pBestType:
  1708.             {
  1709.             data.SetDescTypeData(this->BestType(t, pContents));
  1710.             }
  1711.             break;
  1712.         
  1713.         case pDefaultType:
  1714.             {
  1715.             data.SetDescTypeData(this->DefaultType(t, pContents));
  1716.             }
  1717.             break;
  1718.         
  1719.         case pIndex:
  1720.             {
  1721.             TAbstractScriptableObject* parent = this->ParentObject(t);
  1722.             long i = 0;
  1723.             if(parent == nil)
  1724.                 FailErr(errAENoSuchObject);
  1725.             
  1726.             TAbstractObjectIterator* siblingIterator = parent->ElementIterator(t);
  1727.             for(siblingIterator->Reset(t); siblingIterator->More(t); siblingIterator->Next(t))
  1728.                 {
  1729.                 ++i;
  1730.                 TAbstractScriptableObject* token = siblingIterator->Current(t);
  1731.                 Boolean match = this->ObjectRepresentedInToken(t, token);
  1732.                 token->DisposeDesignator();
  1733.                 if(match)
  1734.                     {
  1735.                     data.SetSInt32Data(i);
  1736.                     break;
  1737.                     }
  1738.                 }
  1739.             
  1740.             if(data.IsNullDescriptor())
  1741.                 FailErr(errAENoSuchObject);
  1742.             }
  1743.             break;
  1744.  
  1745.         case pProperties:
  1746.             {
  1747.             data = this->GetProperties(t, desiredType);
  1748.             }
  1749.             break;
  1750.  
  1751.         case pContents:
  1752.             {
  1753.             if(desiredType == typeObjectSpecifier)
  1754.                 data = this->BuildObjectSpecifier(t);
  1755.             else
  1756.                 Throw(errAECantSupplyType);
  1757.             }
  1758.             break;
  1759.             
  1760.         default:
  1761.             {
  1762.             TAbstractScriptableObject* propertyToken = nil;
  1763.             TAbstractScriptableObject* representative = nil;
  1764.             OSErr err = noErr;
  1765.             
  1766.             NOREGISTER(propertyToken);
  1767.             NOREGISTER(representative);
  1768.             
  1769.             {Try
  1770.                 {
  1771.                 //
  1772.                 // First, try to get the property from our representative
  1773.                 // (if any)
  1774.                 //
  1775.                 representative = this->RepresentativeScriptingObject(t);
  1776.                 if(representative != nil)
  1777.                     data = representative->GetProperty(t, propertyIdentifer, desiredType, additionalInfo);
  1778.                 else
  1779.                     err = errAENoSuchObject;
  1780.                 }
  1781.             Catch(err)
  1782.                 {
  1783.                 }}
  1784.             if(representative != nil)
  1785.                 representative->DisposeDesignator();
  1786.  
  1787.             if(err != noErr)
  1788.                 {
  1789.                 err = noErr;
  1790.                 Try
  1791.                     {
  1792.                     //
  1793.                     // AccessByProperty does not always return a TGenericProperty;
  1794.                     // try to generate a property token using AccessByProperty if
  1795.                     // an implementation for the specified property does not exist.
  1796.                     // This is a little slower, but it's more robust.
  1797.                     //
  1798.                     // n.b. AccessByProperty will fail with errAENoSuchObject if
  1799.                     // the property does not exist.
  1800.                     //
  1801.                     propertyToken = this->AccessByProperty(t, propertyIdentifer);
  1802.     
  1803.                     //
  1804.                     // Test for propertyToken being a generic property token.
  1805.                     // If it is, then we'll throw ourselves into an infinite loop
  1806.                     // when we call GetData!
  1807.                     //
  1808.                     if(propertyToken->DerivedFrom(clGenericProperty))
  1809.                         {
  1810.                         ASSERT(false);
  1811.                         Throw(errAENoSuchObject);
  1812.                         }
  1813.                     data = propertyToken->GetDataOfType(t, pContents, desiredType);
  1814.                     }
  1815.                 Catch(err)
  1816.                     {
  1817.                     if(propertyToken != nil)
  1818.                         propertyToken->DisposeDesignator();    
  1819.                     Throw(err);
  1820.                     }
  1821.                 }
  1822.             if(propertyToken != nil)
  1823.                 propertyToken->DisposeDesignator();            
  1824.             }
  1825.         }
  1826.     
  1827.     return data;
  1828.     } // TAbstractScriptableObject::GetProperty 
  1829.  
  1830. //----------------------------------------------------------------------------------------
  1831. // TAbstractScriptableObject::SetProperty: 
  1832. //----------------------------------------------------------------------------------------
  1833. void TAbstractScriptableObject::SetProperty(const TAETransaction& t, DescType propertyIdentifer, TDescriptor& data, unsigned long additionalInfo)
  1834.     {
  1835.     switch(propertyIdentifer)
  1836.         {
  1837.         case pClass:
  1838.         case pBestType:
  1839.         case pDefaultType:
  1840.         case pIndex:
  1841.             {
  1842.             Throw(errAENotModifiable);
  1843.             }
  1844.  
  1845.         case pProperties:
  1846.             {
  1847.             this->SetProperties(t, data);
  1848.             }
  1849.             break;
  1850.         
  1851.         default:
  1852.             {
  1853.             TAbstractScriptableObject* propertyToken = nil;
  1854.             TAbstractScriptableObject* representative = nil;
  1855.             OSErr err = noErr;
  1856.             
  1857.             NOREGISTER(propertyToken);
  1858.             NOREGISTER(representative);
  1859.             
  1860.             {Try
  1861.                 {
  1862.                 //
  1863.                 // First, try to get the property from our representative
  1864.                 // (if any)
  1865.                 //
  1866.                 representative = this->RepresentativeScriptingObject(t);
  1867.                 if(representative != nil)
  1868.                     representative->SetProperty(t, propertyIdentifer, data, additionalInfo);
  1869.                 else
  1870.                     err = errAENoSuchObject;
  1871.                 }
  1872.             Catch(err)
  1873.                 {
  1874.                 }}
  1875.             if(representative != nil)
  1876.                 representative->DisposeDesignator();
  1877.  
  1878.             if(err != noErr)
  1879.                 {
  1880.                 err = noErr;
  1881.                 Try
  1882.                     {
  1883.                     //
  1884.                     // AccessByProperty does not always return a TGenericProperty;
  1885.                     // try to generate a property token using AccessByProperty if
  1886.                     // an implementation for the specified property does not exist.
  1887.                     // This is a little slower, but it's more robust.
  1888.                     //
  1889.                     // n.b. AccessByProperty will fail with errAENoSuchObject if
  1890.                     // the property does not exist.
  1891.                     //
  1892.                     propertyToken = this->AccessByProperty(t, propertyIdentifer);
  1893.     
  1894.                     //
  1895.                     // Test for propertyToken being a generic property token.
  1896.                     // If it is, then we'll throw ourselves into an infinite loop
  1897.                     // when we call SetData!
  1898.                     //
  1899.                     if(propertyToken->DerivedFrom(clGenericProperty))
  1900.                         {
  1901.                         ASSERT(false);
  1902.                         Throw(errAENoSuchObject);
  1903.                         }
  1904.                     propertyToken->SetData(t, data);
  1905.                     }
  1906.                 Catch(err)
  1907.                     {
  1908.                     if(propertyToken != nil)
  1909.                         propertyToken->DisposeDesignator();    
  1910.                     Throw(err);
  1911.                     }
  1912.                 }
  1913.             if(propertyToken != nil)
  1914.                 propertyToken->DisposeDesignator();            
  1915.             
  1916.             }
  1917.         }
  1918.     } // TAbstractScriptableObject::SetProperty 
  1919.  
  1920. //----------------------------------------------------------------------------------------
  1921. // TAbstractScriptableObject::SetProperties:
  1922. //
  1923. // Set a whole bunch of properties all with one method call.  Currently, this method is
  1924. // only used by the "Create Element" event.  It might be a good idea to have a
  1925. // "Set Properties" event, though, as there are likely a number of instances where an
  1926. // application would like to set a large number of properties in the same object or set
  1927. // of objects without having to pay the IPC & Resolve overhead for each and every
  1928. // property being set.
  1929. //----------------------------------------------------------------------------------------
  1930. void TAbstractScriptableObject::SetProperties(const TAETransaction& t, TDescriptor& properties)
  1931.     {
  1932.     Boolean atLeastOneWorked = false;
  1933.     OSErr err = noErr;
  1934.     
  1935.     for(TDescriptorIterator iter(properties); iter.More(); iter.Next())
  1936.         {
  1937.         // DebugNumber("\pBegin loop for property @", keyword);
  1938.         
  1939.         //
  1940.         // •••    What should we do about errors here?  If one
  1941.         //        of the specified properties does not exist,
  1942.         //        cannot be modified or does not accept the
  1943.         //        data type provided, we'll get an exception.
  1944.         //        However, we would also like to try to set all
  1945.         //        of the other properties in the record.  Right
  1946.         //        now we just swallow errors.  If we reported
  1947.         //        them, we would have the problem that we might
  1948.         //        have more than one error number to return.  We
  1949.         //        could just return the last error, or perhaps
  1950.         //        we could return the error code if only one
  1951.         //        property signaled an exception, and invent a
  1952.         //        new error code that means "I saw more than one
  1953.         //        error go by."
  1954.         //
  1955.         // If we ever did care to report errors even if there
  1956.         // was at least one object that worked correctly, we
  1957.         // might want to consider ignoring 'not modifiable'
  1958.         // errors.
  1959.         //
  1960.         Try
  1961.             {
  1962.             this->SetProperty(t,iter.CurrentKeyword(),iter.Current());
  1963.             atLeastOneWorked = true;
  1964.             }
  1965.         Catch(err)
  1966.             {
  1967.             }
  1968.         }
  1969.     if(atLeastOneWorked == false)
  1970.         FailErr(err);
  1971.     } // TAbstractScriptableObject::SetProperties 
  1972.  
  1973. //----------------------------------------------------------------------------------------
  1974. // TAbstractScriptableObject::GetProperties:
  1975. //
  1976. // Get a whole bunch of properties all with one method call.  Currently, this method 
  1977. // always returns _all_ published properties for the specified object.  In the future
  1978. // it might be nice if we could include an input parameter that listed the properties
  1979. // that we were interested in; if unspecified, then all would be returned.
  1980. //
  1981. // The desired type is passed on to all of the properties of this class; the
  1982. // "properties" property _always_ returns an AERecord.
  1983. //----------------------------------------------------------------------------------------
  1984. TDescriptor TAbstractScriptableObject::GetProperties(const TAETransaction& t, DescType desiredType)
  1985.     {
  1986.     TDescriptor properties;
  1987.     TDescriptor data;
  1988.     Boolean atLeastOneWorked = false;
  1989.     OSErr err = noErr;
  1990.  
  1991.     properties.MakeAERecord();
  1992.     
  1993.     //
  1994.     // Loop from the number of properties down to 1
  1995.     // so that pName and the other properties of
  1996.     // TAbstractScriptable object will always be
  1997.     // listed first.
  1998.     //
  1999.     long numberOfProperties = this->NumberOfProperties(t);
  2000.     for(long i=numberOfProperties;i>0;--i)
  2001.         {
  2002.         const TPropertyDescription* propertyDescription = this->DescriptionOfNthProperty(t, i);
  2003.         
  2004.         //
  2005.         // Skip any property in the property table that is marked for exclusion
  2006.         //
  2007.         if(DontIncludeInPropertiesProperty(propertyDescription->AdditionalInfo()) == false)
  2008.             {
  2009.             Try
  2010.                 {
  2011.                 //
  2012.                 // Look up the data type to get; usually it will be the default type
  2013.                 // or the best type for an individual property, but sometimes another
  2014.                 // data type might be specified; in that case, only properties that
  2015.                 // can return the specified type will be included in the result.
  2016.                 //
  2017.                 DescType typeToGet = desiredType;
  2018.                 if(desiredType == typeWildCard)
  2019.                     typeToGet = propertyDescription->DefaultType();
  2020.                 if(desiredType == typeBest)
  2021.                     typeToGet = propertyDescription->BestType();
  2022.                 
  2023.                 //
  2024.                 // If the type to get is 'typeNull', then a description of the
  2025.                 // property without any of its data is returned.
  2026.                 //
  2027.                 // ◊Script:        We should try to coerce the results of 'GetProperty'
  2028.                 //                to 'typeToGet' after it returns, just like GetDataOfType
  2029.                 //                does.
  2030.                 //
  2031.                 if(typeToGet != typeNull)
  2032.                     {
  2033.                     data = this->GetProperty(t, propertyDescription->PropertyIdentifier(),typeToGet, propertyDescription->AdditionalInfo());
  2034.                     this->CoerceResultToRequestedType(data, typeToGet);
  2035.                     }
  2036.                 properties.PutDescriptorParameter(propertyDescription->PropertyIdentifier(), data);
  2037.                 atLeastOneWorked = true;
  2038.                 }
  2039.             Catch(err)
  2040.                 {
  2041.                 }
  2042.         
  2043.             data.Dispose();
  2044.             }
  2045.         }
  2046.  
  2047.     if(atLeastOneWorked == false)
  2048.         {
  2049.         properties.Dispose();
  2050.         FailErr(err);
  2051.         }
  2052.         
  2053.     return properties;
  2054.     } // TAbstractScriptableObject::GetProperties 
  2055.  
  2056. //----------------------------------------------------------------------------------------
  2057. // TAbstractScriptableObject::ResolveSpecifierAndGetData
  2058. //
  2059. // Given an object specifier, resolve it and call Get Data.
  2060. //----------------------------------------------------------------------------------------
  2061. TDescriptor TAbstractScriptableObject::ResolveSpecifierAndGetData(const TAETransaction& t, TDescriptor objectSpecifier)
  2062.     {
  2063.     TTokenDescriptor sourceToken;
  2064.     TDescriptor resolvedData;
  2065.     OSErr err = noErr;
  2066.     
  2067.     Try
  2068.         {
  2069.         sourceToken = objectSpecifier.Resolve(t);
  2070.         DescType bestTypeForDestination = this->BestType(t, pContents);
  2071.         TAbstractScriptableObject* token = sourceToken.TokenObject();
  2072.         
  2073.         //
  2074.         // We would like to get data from the resolved token using
  2075.         // the best type of this object; if that is not possible, though,
  2076.         // then we get the best data type of the resolved token, and hope
  2077.         // that it can be coerced into the best type for this object.
  2078.         //
  2079.         DescType dataType = (token->CanReturnDataOfType(t, pContents, bestTypeForDestination) ? bestTypeForDestination : token->BestType(t, pContents) );
  2080.         resolvedData = token->GetDataOfType(t, pContents, dataType);
  2081.     
  2082.         sourceToken.DisposeToken();
  2083.         }
  2084.     Catch(err)
  2085.         {
  2086.         sourceToken.DisposeToken();
  2087.         resolvedData.Dispose();
  2088.         }
  2089.         
  2090.     return resolvedData;
  2091.     } // TAbstractScriptableObject::ResolveSpecifierAndGetData
  2092.     
  2093. //----------------------------------------------------------------------------------------
  2094. // TAbstractScriptableObject::ResolveKeyData:
  2095. //
  2096. // The purpose of this routine is to convert object specifiers passed in as key
  2097. // data in a 'Set Data' event into data in the best type supported by the token.  Other
  2098. // conversions may be done by other tokens.
  2099. //
  2100. // This method should either return a new descriptor (which will be disposed of by
  2101. // the SetData handler) or a descriptor of typeNull.  It should _never_ return
  2102. // the keyData descriptor itself (although it could return a copy of the keydata,
  2103. // this is no different than returning typeNull).
  2104. //
  2105. // DANGER:  The code here is very simple, but the logic is quite complex.  Fortunately,
  2106. // you should never need to override or call ResolveKeyData.
  2107. //----------------------------------------------------------------------------------------
  2108. TDescriptor TAbstractScriptableObject::ResolveKeyData(const TAETransaction& t, TDescriptor keyData)
  2109.     {
  2110.     TDescriptor resolvedData;
  2111.     OSErr err = noErr;
  2112.     
  2113.     Try
  2114.         {
  2115.         //
  2116.         // If the key data is an object specifier, and the best type
  2117.         // of this token (the _destination_ token--the object that
  2118.         // will be receiving the results of the set data event) is not
  2119.         // typeObjectSpecifier, then try to extract data from the source
  2120.         // token (resolved from the keyData object specifier) in the best
  2121.         // data type of the destination token if possible, or in the best
  2122.         // type of the source token if the source cannot provide the
  2123.         // destination's best data type.
  2124.         //
  2125.         // Why check for BestType == typeObjectSpecifier?
  2126.         //
  2127.         // If doing a set data on pSelection, the key data will always
  2128.         // be type object specifier.  pSelection expects an object
  2129.         // specifier, though, so it doesn't make sense to try to
  2130.         // resolve the key data here.
  2131.         //
  2132.         if((keyData.DescriptorType() == typeObjectSpecifier) && (this->BestType(t, pContents) != typeObjectSpecifier))
  2133.             {
  2134.             //
  2135.             // ••• Strange exception:
  2136.             //
  2137.             // Some properties (e.g. the view of a window) accept an
  2138.             // object specifier of a property in place of an enumeration.
  2139.             // For example, "set view of window 1 to name" results in
  2140.             // keyData that is an object specifier whose key data is
  2141.             // pName, and whose parent container is the null container.
  2142.             // This object specifier is treated the same as an enumeration
  2143.             // whose value is pName.
  2144.             //
  2145.             // Any object specifier in the key data whose key form is
  2146.             // keyPropertyID may be converted into an enumeration (GetEnumeration
  2147.             // will do this translation).  Note there is an ambiguity
  2148.             // here:  is "set x to name" supposed to pass the enumeration
  2149.             // pName to object x, or is it supposed to pass (get data
  2150.             // pName of null container) to object x (the later is the
  2151.             // normal case)?
  2152.             //
  2153.             // We pass the enumeration if and only if the best type
  2154.             // for object x is typeEnumeration.  Note, however, that
  2155.             // it is also possible to say "set view of window 1 to
  2156.             // view of window 2"; in this case, ResolveKeyData will
  2157.             // do the wrong thing and pass 'pView' to the set data
  2158.             // method of the "view of window 1" property, which will
  2159.             // fail.  The set data handler is smart enough to detect
  2160.             // this situation and correct for it, though.
  2161.             //
  2162.             // Hardest cases:
  2163.             //
  2164.             // tell window 1 of application "Finder"
  2165.             //        set view to view of window 2
  2166.             // end tell
  2167.             //
  2168.             // (This is the case corrected for in the set data handler;
  2169.             // first, view of window 1 is set to 'pView'; this fails,
  2170.             // so set data resolves view of window 2 and tries again.)
  2171.             //
  2172.             // tell window 1 of application "Finder"
  2173.             //        set view to name
  2174.             // end tell
  2175.             //
  2176.             // (AppleScript sends an object specifier for "name of
  2177.             // window 1".  We assume that "pName" was intended, and
  2178.             // do the right thing.)
  2179.             //
  2180.             // tell application "Finder"
  2181.             //        set view of window 1 to name of window 1
  2182.             // end tell
  2183.             //
  2184.             // (This should be an error, but we confuse it with the
  2185.             // above case and change the view of window 1 to name.)
  2186.             //
  2187.             Boolean shouldDoResolution = true;
  2188.             OSErr unusedErr = noErr;
  2189.             
  2190.             Try
  2191.                 {
  2192.                 //
  2193.                 // If the best type of the object is typeEnumeration, and
  2194.                 // we can convert the object specifier in keyData into an
  2195.                 // enumeration, then we DO NOT want to resolve the keyData.
  2196.                 //
  2197.                 if(this->BestType(t, pContents) == typeEnumeration)
  2198.                     {
  2199.                     DescType resolvedEnumeration = keyData.GetDescTypeData(typeEnumeration);
  2200.                     resolvedData.PutDescTypeParameter(resolvedEnumeration, typeEnumeration);
  2201.                     shouldDoResolution = false;
  2202.                     }
  2203.                 }
  2204.             Catch(unusedErr)
  2205.                 {
  2206.                 }
  2207.             
  2208.             //
  2209.             // In all other cases, resolve the object specifier, call Get Data
  2210.             // on the resulting token, and pass the result on to the object
  2211.             // that SetData is being called on.
  2212.             //
  2213.             if(shouldDoResolution == true)
  2214.                 resolvedData = ResolveSpecifierAndGetData(t, keyData);
  2215.             }
  2216.         }
  2217.     Catch(err)
  2218.         {
  2219.         resolvedData.Dispose();
  2220.         
  2221.         Throw(err);
  2222.         }
  2223.     
  2224.     return resolvedData;
  2225.     } // TAbstractScriptableObject::ResolveKeyData 
  2226.  
  2227. //----------------------------------------------------------------------------------------
  2228. // TAbstractScriptableObject::CompareDescriptor: 
  2229. //
  2230. // This method compares this token with the descriptor provided in 'descOrObject.'
  2231. // 'descOrObject' can contain either literal data (e.g. a string or an integer), or
  2232. // it could contain an object specifier to some other object to compare against.
  2233. // If an object specifier is passed in, then we resolve it and try to get the best
  2234. // data type for _this_ token; if the comparison token cannot provide that data type,
  2235. // then we try to get its best data type and do a coercion.
  2236. //----------------------------------------------------------------------------------------
  2237. Boolean TAbstractScriptableObject::CompareDescriptor(const TAETransaction& t, DescType comparisonOperator, TDescriptor& descOrObject)
  2238.     {
  2239.     Boolean comparisonResult = true;
  2240.     
  2241.     TDescriptor ourData;
  2242.     TDescriptor compareWith;
  2243.     OSErr err = noErr;
  2244.     
  2245.     Try
  2246.         {
  2247.         //
  2248.         // Compare with 'descOrObject,' unless we need to coerce it,
  2249.         // in which case we will compare with the coerced descriptor 'compareWith'
  2250.         //
  2251.         TDescriptor* compareWithRef = &descOrObject;
  2252.         
  2253.         //
  2254.         // First, we try to coerce the comparison object to the
  2255.         // best data type for this object, if possible, to make
  2256.         // it more likely that we can obtain the same type of
  2257.         // data from this object.
  2258.         //
  2259.         DescType ourBestType = this->BestType(t, pContents);
  2260.         if((compareWith.DescriptorType() != ourBestType) && (ourBestType != typeWildCard))
  2261.             {
  2262.             OSErr coerceErr = noErr;
  2263.             compareWith = descOrObject.AttemptToCoerce(this->BestType(t, pContents), coerceErr);
  2264.  
  2265.             //
  2266.             // If we cannot coerce to the best type, try to coerce
  2267.             // to some standard data type so that we will be more
  2268.             // likely to be able to get a compatable data type.
  2269.             //
  2270.             if(coerceErr != noErr)
  2271.                 compareWith = descOrObject.CoerceToStandardType();
  2272.             
  2273.             //
  2274.             // If we were able to coerce to our best type or
  2275.             // to some standard type, then use the coerced data
  2276.             // to do the comparison.
  2277.             //
  2278.             if(compareWith.IsNullDescriptor() == false)
  2279.                 compareWithRef = &compareWith;
  2280.             }
  2281.         
  2282.         //
  2283.         // If we can get data from this token in the same data type
  2284.         // as the comparison object, then do so; otherwise, get the
  2285.         // best data type for this object and try to coerce it to
  2286.         // the same type as the data that was passed to us
  2287.         //
  2288.         if(this->CanReturnDataOfType(t, pContents, compareWithRef->DescriptorType()))
  2289.             {
  2290.             ourData = this->GetDataOfType(t, pContents, compareWithRef->DescriptorType());
  2291.             }
  2292.         else
  2293.             {
  2294.             ourData = this->GetDataOfType(t, pContents, this->BestType(t, pContents));
  2295.             ourData.CoerceInPlace(compareWithRef->DescriptorType());
  2296.             }
  2297.         
  2298.         //
  2299.         // Once we have two peices of data in the same type,
  2300.         // doing the comparison is relatively straightforward
  2301.         //
  2302.         // Note that TDescriptor::Compare assumes that the
  2303.         // two objects are of the same type, and fails if
  2304.         // they are not.
  2305.         //
  2306.         comparisonResult = ourData.Compare(comparisonOperator,*compareWithRef);
  2307.         ourData.Dispose();
  2308.         compareWith.Dispose();
  2309.         }
  2310.     Catch(err)
  2311.         {
  2312.         ourData.Dispose();
  2313.         compareWith.Dispose();
  2314.         Throw(err);
  2315.         }
  2316.     
  2317.     return comparisonResult;
  2318.     } // TAbstractScriptableObject::CompareDescriptor 
  2319.  
  2320. //----------------------------------------------------------------------------------------
  2321. // TAbstractScriptableObject::Compare: 
  2322. //
  2323. // This is one of two 'Compare' methods.  This compare method compares this token
  2324. // with every token in the 'compareWith' parameter.
  2325. //----------------------------------------------------------------------------------------
  2326. Boolean TAbstractScriptableObject::Compare(const TAETransaction& t, DescType comparisonOperator, TAbstractScriptableObject* compareWith)
  2327.     {
  2328.     Boolean comparisonResult = false;
  2329.         
  2330.     TDescriptor compareData;
  2331.     DescType dataTypeToCompare;
  2332.     
  2333.     //
  2334.     // If the token we are comparing with can return our best type, then
  2335.     // ask it for our best type.
  2336.     //
  2337.     if(compareWith->CanReturnDataOfType(t, pContents, this->BestType(t, pContents)))
  2338.         dataTypeToCompare = this->BestType(t, pContents);
  2339.     else
  2340.         dataTypeToCompare = compareWith->BestType(t, pContents);
  2341.     
  2342.     //
  2343.     // GetDataOfType will always return the requested type, or fail.
  2344.     //
  2345.     compareData = compareWith->GetDataOfType(t, pContents, dataTypeToCompare);
  2346.     
  2347.     //
  2348.     // Once we have solid data to compare (not a specifier),
  2349.     // we can call CompareDescriptor
  2350.     //
  2351.     // ◊Script: It would be bad if we got an object specifier back
  2352.     // here, as our technique for resolving it would normally
  2353.     // be to make a recursive call to this "Compare" routine;
  2354.     // however, doing that would throw us into an infinite
  2355.     // loop, because the next iteration would also return an
  2356.     // object specifier.
  2357.     //
  2358.     // The case we are probably concerned with is when we
  2359.     // compare the "selection" to something.  Doing this
  2360.     // seems to work without involving our Compare callback,
  2361.     // though.  Therefore, we just return 'false' if we
  2362.     // get an object specifier.  Perhaps we should fail
  2363.     // with some form of 'not handled' error, though.
  2364.     //
  2365.     if(compareData.DescriptorType() != typeObjectSpecifier)
  2366.         comparisonResult = this->CompareDescriptor(t, comparisonOperator,compareData);
  2367.     
  2368.     compareData.Dispose();
  2369.  
  2370.     return comparisonResult;
  2371.     } // TAbstractScriptableObject::Compare 
  2372.  
  2373. //----------------------------------------------------------------------------------------
  2374. // TAbstractScriptableObject::Compare: 
  2375. //
  2376. // This method compares this token with the descriptor provided in 'descOrObject.'
  2377. // 'descOrObject' can contain either literal data (e.g. a string or an integer), or
  2378. // it could contain an object specifier to some other object to compare against.
  2379. // If an object specifier is passed in, then we resolve it and try to get the best
  2380. // data type for _this_ token; if the comparison token cannot provide that data type,
  2381. // then we try to get its best data type and do a coercion.
  2382. //----------------------------------------------------------------------------------------
  2383. Boolean TAbstractScriptableObject::Compare(const TAETransaction& t, DescType comparisonOperator, TDescriptor& descOrObject)
  2384.     {
  2385.     Boolean comparisonResult = true;
  2386.     Boolean couldGetOSpec = false;
  2387.     OSErr err = noErr;
  2388.     
  2389.     if(descOrObject.DescriptorType() == typeObjectSpecifier)
  2390.         {
  2391.         TTokenDescriptor compareTokenDesc;
  2392.         
  2393.         //
  2394.         // First try:  try to resolve the object specifier and compare
  2395.         // this token with the best data from the resolved specifier
  2396.         //
  2397.         Try
  2398.             {
  2399.             compareTokenDesc = descOrObject.Resolve(t);
  2400.             couldGetOSpec = true;
  2401.             }
  2402.         Catch(err)
  2403.             {
  2404.             }
  2405.         
  2406.         //
  2407.         // If we resolved, try to do a get data
  2408.         //
  2409.         if(couldGetOSpec)
  2410.             {
  2411.             Try
  2412.                 {
  2413.                 comparisonResult = this->Compare(t, comparisonOperator,compareTokenDesc.TokenObject());
  2414.                 }
  2415.             Catch(err)
  2416.                 {
  2417.                 compareTokenDesc.DisposeToken();
  2418.                 Throw(err);
  2419.                 }
  2420.             }
  2421.         
  2422.         compareTokenDesc.DisposeToken();
  2423.         }
  2424.     
  2425.     //
  2426.     // If we couldn't resolve the specifier (or if it wasn't an object specifier to begin with),
  2427.     // then call the simple compare routine
  2428.     //
  2429.     if(couldGetOSpec == false)
  2430.         {
  2431.         comparisonResult = this->CompareDescriptor(t, comparisonOperator, descOrObject);
  2432.         }
  2433.     
  2434.     return comparisonResult;
  2435.     } // TAbstractScriptableObject::Compare 
  2436.  
  2437. //----------------------------------------------------------------------------------------
  2438. // TAbstractScriptableObject::CompareProperty: 
  2439. //
  2440. // To avoid extra memory allocations (both for 'testDesc', and
  2441. // possibly another in 'GetProperty', if AccessByProperty/GetData
  2442. // is called), then this routine may be overridden and a direct
  2443. // compare may be substituted.  Doing this is just a performance
  2444. // optimization, however; the generic code below is sufficient
  2445. // to handle any property compare that is needed.
  2446. //----------------------------------------------------------------------------------------
  2447. Boolean TAbstractScriptableObject::CompareProperty(const TAETransaction& t, DescType propertyIdentifier, DescType comparisonOperator, TDescriptor compareWith)
  2448.     {
  2449.     Boolean result = false;
  2450.     Boolean tested = false;
  2451.  
  2452.     //
  2453.     // Some properties are handled in a special way
  2454.     //
  2455.     switch(propertyIdentifier)
  2456.         {
  2457.         case pClass:
  2458.             {
  2459.             //
  2460.             // "class contains cXXX" is an alternate way to
  2461.             // represent "this object is derived from class
  2462.             // cXXX" (we need to support this in case someone
  2463.             // wishes to encode class membership as a term
  2464.             // to test in the search spec rather than pass it
  2465.             // in as a separate parameter.
  2466.             //
  2467.             if(comparisonOperator == kAEContains)
  2468.                 {
  2469.                 result = this->DerivedFromOSLClass(t, compareWith.GetDescTypeData());
  2470.                 tested = true;
  2471.                 }
  2472.             }
  2473.             break;
  2474.         }
  2475.     
  2476.     //
  2477.     // By default, 
  2478.     //
  2479.     if(tested == false)
  2480.         {
  2481.         TDescriptor testDesc = this->GetProperty(t, propertyIdentifier, typeWildCard);
  2482.         result = testDesc.Compare(comparisonOperator, compareWith);
  2483.         testDesc.Dispose();
  2484.         }
  2485.         
  2486.     return result;
  2487.     } // TAbstractScriptableObject::CompareProperty 
  2488.  
  2489. //----------------------------------------------------------------------------------------
  2490. // TAbstractScriptableObject::ParseComparisonOperator: 
  2491. //----------------------------------------------------------------------------------------
  2492. TComparisonOperand* TAbstractScriptableObject::ParseComparisonOperand(TDescriptor& operand)
  2493.     {
  2494.     TComparisonOperand* result = nil;
  2495.     
  2496.     if(operand.DescriptorType() == typeObjectSpecifier)
  2497.         {
  2498.         //
  2499.         // First, parse the object specifier and determine if it
  2500.         // is relative to the object being examined or not.
  2501.         //
  2502.         TAbstractObjectSpecifier* parsedSpecifier = ParseObjectSpecifier(operand);
  2503.         Boolean isRelativeToObjectBeingExamined = parsedSpecifier->RootContainerIsObjectBeingExamined();
  2504.         
  2505.         //
  2506.         // Assume that we are going to be comparing against the
  2507.         // 'pContents' property of the specified object.  If the
  2508.         // first portion of the object specifier is a property,
  2509.         // however, then we can extract the property from the
  2510.         // specifier and use some of the optimized comparison
  2511.         // code available to us.
  2512.         //
  2513.         DescType propertyToCompare = pContents;
  2514.         if(parsedSpecifier->KeyForm() == formPropertyID)
  2515.             {
  2516.             DescType desiredClass;
  2517.             DescType keyForm;
  2518.             TDescriptor keyData;
  2519.             
  2520.             TAbstractObjectSpecifier* formerSpecifier = parsedSpecifier;
  2521.             parsedSpecifier = formerSpecifier->ExtractParentSpecifier(desiredClass, keyForm, keyData);
  2522.             propertyToCompare = keyData.GetDescTypeData();
  2523.             
  2524.             //
  2525.             // As a further optimization, we don't need the parsed specifier
  2526.             // if it is just a TObjectBeingExamined; nil is just as good
  2527.             // (better, even, since it doesn't require is to clone the object
  2528.             // being examined, like the TObjectBeingExamined would).
  2529.             //
  2530.             if(parsedSpecifier->KeyForm() == typeObjectBeingExamined)
  2531.                 {
  2532.                 delete parsedSpecifier;
  2533.                 parsedSpecifier = nil;
  2534.                 }
  2535.                 
  2536.             //
  2537.             // Delete the former specifier now that we've extracted
  2538.             // the property specifier from it.  n.b. this also deletes
  2539.             // the descriptor 'keyData'.
  2540.             //
  2541.             delete formerSpecifier;
  2542.             keyData.ClearDescriptor();
  2543.             }
  2544.         
  2545.         //
  2546.         // Now build an object that knows how to compare a property
  2547.         // of some object 
  2548.         //
  2549.         result = new TPropertyComparisonOperand(propertyToCompare, parsedSpecifier, isRelativeToObjectBeingExamined);
  2550.         }
  2551.     else
  2552.         {
  2553.         result = new TConstantComparisonOperand(operand);
  2554.         operand.ClearDescriptor();
  2555.         }
  2556.     
  2557.     return result;
  2558.     }
  2559.     
  2560. //----------------------------------------------------------------------------------------
  2561. // TAbstractScriptableObject::ParseComparisonOperator: 
  2562. //----------------------------------------------------------------------------------------
  2563. TAbstractSearchSpec* TAbstractScriptableObject::ParseComparisonOperator(DescType comparisonOperator, TDescriptor& object1, TDescriptor& object2)
  2564.     {
  2565.     TAbstractSearchSpec* searchSpec = nil;
  2566. //    DescType desiredClass;
  2567. //    DescType keyForm;
  2568.     TDescriptor keyData;
  2569.     TDescriptor containerDesc;
  2570.     OSErr err = noErr;
  2571.         
  2572.     Try
  2573.         {
  2574.         //
  2575.         // We assume that object 1 is an object specifier, and
  2576.         // that object 2 is literal data.  This is almost always
  2577.         // going to be the case; however, we do check to see if
  2578.         // object 1 and object 2 need to be reversed, should
  2579.         // object 2 be the object specifier and object 1 be the
  2580.         // literal data.  Note that this is not strictly necessary,
  2581.         // but we do it to allow for performance optimizations
  2582.         // involving comparing a property of some object with
  2583.         // literal data, since there are no optimizations when
  2584.         // comparing literal data with a property of some object. 
  2585.         //
  2586.         if((object1.DescriptorType() != typeObjectSpecifier) || (object2.DescriptorType() == typeObjectSpecifier))
  2587.             {
  2588.             TDescriptor tmp;
  2589.             
  2590.             comparisonOperator = ReverseComparisonOperator(comparisonOperator);
  2591.             tmp.AdoptDescriptor(object2);
  2592.             object2.AdoptDescriptor(object1);
  2593.             object1.AdoptDescriptor(tmp);
  2594.             }
  2595.         
  2596.         //
  2597.         // Create comparison operands and a search specification for this
  2598.         // comparison operation.
  2599.         //
  2600.         TComparisonOperand* operand1 = this->ParseComparisonOperand(object1);
  2601.         TComparisonOperand* operand2 = this->ParseComparisonOperand(object2);
  2602.         searchSpec = new TGenericSearchSpec(comparisonOperator, operand1, operand2);
  2603.         }
  2604.     Catch(err)
  2605.         {
  2606.         containerDesc.Dispose();
  2607.         keyData.Dispose();
  2608.  
  2609.         Throw(err);
  2610.         }
  2611.  
  2612.     containerDesc.Dispose();
  2613.     keyData.Dispose();
  2614.     
  2615.     return searchSpec;
  2616.     } // TAbstractScriptableObject::ParseComparisonOperator 
  2617.  
  2618. //----------------------------------------------------------------------------------------
  2619. // TAbstractScriptableObject::ParseLogicalDescriptor: 
  2620. //----------------------------------------------------------------------------------------
  2621. TAbstractSearchSpec* TAbstractScriptableObject::ParseLogicalDescriptor(DescType logicalOperator, TDescriptor logicalTerms)
  2622.     {
  2623.     TAbstractSearchSpec* searchSpec = nil;
  2624.         
  2625.     switch(logicalOperator)
  2626.         {
  2627.         case kAENOT:
  2628.         case kAEOR:
  2629.         case kAEAND:
  2630.             {
  2631.             TAbstractSearchSpec* oneSpecification = nil;
  2632.             AListOf<TAbstractSearchSpec*>* specificationList = nil;
  2633.             
  2634.             //
  2635.             // Iterate over all of the terms in the logical descriptor list
  2636.             //
  2637.             for(TDescriptorIterator iter(logicalTerms); iter.More(); iter.Next())
  2638.                 {
  2639.                 //
  2640.                 // Resolve each term independantly
  2641.                 //
  2642.                 oneSpecification = this->ParseWhoseTest(iter.Current());
  2643.                 
  2644.                 //
  2645.                 // Do we have a list of specifications yet?
  2646.                 //
  2647.                 if(specificationList == nil)
  2648.                     {
  2649.                     //
  2650.                     // I. FIRST TIME THROUGH THE LOOP:
  2651.                     //
  2652.                     // If this is the first term, just remember it for later
  2653.                     // UNLESS the logical operator is NOT, in which case
  2654.                     // we always want to make a list of terms
  2655.                     //
  2656.                     if((searchSpec == nil) && (logicalOperator != kAENOT))
  2657.                         searchSpec = oneSpecification;
  2658.                     //
  2659.                     // If we already have a term (or two), then we must try
  2660.                     // to union the new term with the old term (or one of the
  2661.                     // old terms)
  2662.                     //
  2663.                     else
  2664.                         {
  2665.                         //
  2666.                         // II. SECOND TIME THROUGH THE LOOP
  2667.                         //
  2668.                         // Make a list and add the two terms to it
  2669.                         //
  2670.                         specificationList = new AListOf<TAbstractSearchSpec*>;
  2671.                         if(searchSpec)
  2672.                             specificationList->Add(searchSpec);
  2673.                         specificationList->Add(oneSpecification);
  2674.                         searchSpec = nil;
  2675.                         }
  2676.                     }
  2677.                 else
  2678.                     {
  2679.                     //
  2680.                     // III. EVERY OTHER TIME THROUGH THE LOOP
  2681.                     //
  2682.                     // Add the new term to the list
  2683.                     //
  2684.                     if(oneSpecification != nil)
  2685.                         specificationList->Add(oneSpecification);
  2686.                     }
  2687.                 }
  2688.                 
  2689.                 //
  2690.                 // If we have a specification list, then we need to create
  2691.                 // a logical term to hold it
  2692.                 //
  2693.                 if(specificationList != nil)
  2694.                     {
  2695.                     searchSpec = new TLogicalSearchSpec(logicalOperator, specificationList);
  2696.                     }
  2697.                 
  2698.                 //
  2699.                 // At this point, we'd better have a specifier
  2700.                 //
  2701.                 if(searchSpec == nil)
  2702.                     FailErr(errAEEventNotHandled);
  2703.             }
  2704.             break;
  2705.         
  2706.         default:
  2707.             {
  2708.             FailErr(errAEEventNotHandled);
  2709.             }
  2710.             break;
  2711.         }
  2712.     
  2713.     return searchSpec;
  2714.     } // TAbstractScriptableObject::ParseLogicalDescriptor 
  2715.     
  2716. //----------------------------------------------------------------------------------------
  2717. // TAbstractScriptableObject::ParseWhoseTest: 
  2718. //----------------------------------------------------------------------------------------
  2719. TAbstractSearchSpec* TAbstractScriptableObject::ParseWhoseTest(TDescriptor& whoseDescriptor)
  2720.     {
  2721.     TAbstractSearchSpec* searchSpec = nil;
  2722.     OSErr err = noErr;
  2723.         
  2724.     switch(whoseDescriptor.DescriptorType())
  2725.         {
  2726.         case typeLogicalDescriptor:
  2727.             {
  2728.             DescType logicalOperator;
  2729.             TDescriptor logicalTerms;
  2730.             
  2731.             Try
  2732.                 {
  2733.                 whoseDescriptor.CoerceInPlace(typeAERecord);
  2734.                 
  2735.                 logicalOperator        = whoseDescriptor.GetDescTypeParameter(keyAELogicalOperator, typeEnumeration);
  2736.                 logicalTerms        = whoseDescriptor.GetDescriptorParameter(keyAELogicalTerms);
  2737.             
  2738.                 searchSpec = this->ParseLogicalDescriptor(logicalOperator, logicalTerms);
  2739.                 }
  2740.             Catch(err)
  2741.                 {
  2742.                 logicalTerms.Dispose();
  2743.                 
  2744.                 Throw(err);
  2745.                 }
  2746.             
  2747.             logicalTerms.Dispose();
  2748.             }
  2749.             break;
  2750.         
  2751.         case typeCompDescriptor:
  2752.             {
  2753.             DescType compOperator;
  2754.             TDescriptor object1;
  2755.             TDescriptor object2;
  2756.             
  2757.             Try
  2758.                 {
  2759.                 whoseDescriptor.CoerceInPlace(typeAERecord);
  2760.  
  2761.                 compOperator        = whoseDescriptor.GetDescTypeParameter(keyAECompOperator, typeEnumeration);
  2762.                 object1                = whoseDescriptor.GetDescriptorParameter(keyAEObject1);
  2763.                 object2                = whoseDescriptor.GetDescriptorParameter(keyAEObject2);
  2764.             
  2765.                 searchSpec = this->ParseComparisonOperator(compOperator, object1, object2);
  2766.                 }
  2767.             Catch(err)
  2768.                 {
  2769.                 //object1.Dispose();
  2770.                 //object2.Dispose();
  2771.                 
  2772.                 Throw(err);
  2773.                 }
  2774.             
  2775.             //object1.Dispose();
  2776.             //
  2777.             // ◊Script:  at the moment, we adopt 'object2' in GenericSearchSpec
  2778.             // without cloning it.  Eventually we'll have to make the appropriate
  2779.             // parameters TDescriptor&, so we can null-out object2 if it is adopted
  2780.             //
  2781.             //object2.Dispose();
  2782.             }
  2783.             break;
  2784.         
  2785.         default:
  2786.             {
  2787.             FailErr(errAEEventNotHandled);
  2788.             }
  2789.             break;
  2790.         }
  2791.     
  2792.     return searchSpec;
  2793.     } // TAbstractScriptableObject::ParseWhoseTest 
  2794.     
  2795. //----------------------------------------------------------------------------------------
  2796. // TAbstractScriptableObject::ParseWhoseDescriptor: 
  2797. //----------------------------------------------------------------------------------------
  2798. TAbstractSearchSpec* TAbstractScriptableObject::ParseWhoseDescriptor(TDescriptor whoseDescriptor, TDescriptor& scopeOfSearch)
  2799.     {
  2800.     TAbstractSearchSpec* searchSpec = nil;
  2801.     TDescriptor testDescriptor;
  2802.     TDescriptor whoseRecord;
  2803.     OSErr err = noErr;
  2804.     
  2805.     scopeOfSearch.ClearDescriptor();
  2806.     
  2807.     //
  2808.     // We assume that the descriptor type of the whose descriptor
  2809.     // will always be typeWhoseDescriptor.
  2810.     //
  2811.     if(whoseDescriptor.DescriptorType() != typeWhoseDescriptor)
  2812.         FailErr(errAEEventNotHandled);
  2813.             
  2814.     Try
  2815.         {
  2816.         whoseRecord = whoseDescriptor.Coerce(typeAERecord);
  2817.         
  2818.         scopeOfSearch = whoseRecord.GetDescriptorParameter(keyAEIndex);
  2819.         testDescriptor = whoseRecord.GetDescriptorParameter(keyAETest);
  2820.         searchSpec = this->ParseWhoseTest(testDescriptor);
  2821.         }
  2822.     Catch(err)
  2823.         {
  2824.         scopeOfSearch.Dispose();
  2825.         testDescriptor.Dispose();
  2826.         whoseRecord.Dispose();
  2827.         
  2828.         Throw(err);
  2829.         }
  2830.     
  2831.     testDescriptor.Dispose();
  2832.     whoseRecord.Dispose();
  2833.     
  2834.     return searchSpec;
  2835.     } // TAbstractScriptableObject::ParseWhoseDescriptor 
  2836.  
  2837. //----------------------------------------------------------------------------------------
  2838. // TAbstractScriptableObject::BuildObjectSpecifierForProperty
  2839. //----------------------------------------------------------------------------------------
  2840. TDescriptor TAbstractScriptableObject::BuildObjectSpecifierForProperty(const TAETransaction& t, DescType propertyName)
  2841.     {
  2842.     TDescriptor result;
  2843.     TDescriptor specifier = this->BuildObjectSpecifier(t);
  2844.     
  2845.     if(propertyName == pContents)
  2846.         result.AdoptDescriptor(specifier);
  2847.     else
  2848.         {
  2849.         TDescriptor keyData;
  2850.         keyData.SetDescTypeData(propertyName);
  2851.         result.MakeObjectSpecifier(cProperty, specifier, formPropertyID, keyData, true);
  2852.         }
  2853.     
  2854.     return result;
  2855.     }
  2856.  
  2857. //----------------------------------------------------------------------------------------
  2858. // TAbstractScriptableObject::BuildObjectSpecifier: 
  2859. //----------------------------------------------------------------------------------------
  2860. TDescriptor TAbstractScriptableObject::BuildObjectSpecifier(const TAETransaction& t)
  2861.     {
  2862.     TDescriptor result;
  2863.     
  2864.     TDescriptor container;
  2865.     DescType desiredClass;
  2866.     DescType keyForm;
  2867.     TDescriptor keyData;
  2868.     
  2869.     //
  2870.     // Build an object specifier for the object that we are contained in.
  2871.     //
  2872.     container = this->BuildSpecifierForParent(t);
  2873.     
  2874.     //
  2875.     // Next, gather together the information about this specific object
  2876.     // that will allow the object accessors to return it should it be
  2877.     // asked for again.
  2878.     //
  2879.     desiredClass = this->ObjectClass(t, kObjectRecordedClass);
  2880.     this->MakeKeyDataForSelf(t, keyForm, keyData);
  2881.     
  2882.     //
  2883.     // Note:  if the key form is formPropertyID, then the
  2884.     // desired class must always be cProperty.  ObjectClass(kObjectRecordedClass)
  2885.     // always returns cProperty in the case of properties
  2886.     //
  2887.     if((keyForm == formPropertyID)    && (desiredClass != cProperty))
  2888.         {
  2889.         desiredClass = cProperty;
  2890.         }
  2891.     
  2892.     //
  2893.     // Once we have the individual peices of the object specifier,
  2894.     // ask the AEPackObject library to put it all together for us.
  2895.     //
  2896.     result.MakeObjectSpecifier(desiredClass, container, keyForm, keyData, true);
  2897.  
  2898.     return result;
  2899.     } // TAbstractScriptableObject::BuildObjectSpecifier 
  2900.  
  2901. //----------------------------------------------------------------------------------------
  2902. // TAbstractScriptableObject::MakeKeyDataForSelf: 
  2903. //
  2904. // By default, objects are accessed by name.  If a given object doesn't have a name,
  2905. // or if it should be accessed by some other form, then override this method.
  2906. //----------------------------------------------------------------------------------------
  2907. void TAbstractScriptableObject::MakeKeyDataForSelf(const TAETransaction& t, DescType& keyForm, TDescriptor& keyData)
  2908.     {
  2909.     keyForm = formName;
  2910.     keyData = this->GetProperty(t, pName, typeChar);
  2911.     } // TAbstractScriptableObject::MakeKeyDataForSelf 
  2912.  
  2913. //----------------------------------------------------------------------------------------
  2914. // TAbstractScriptableObject::BuildSpecifierForParent: 
  2915. //
  2916. // This method doesn't actually need to be virtual, since it will be very rare for
  2917. // anyone to ever need to override it, and those who do may override BuildObjectSpecifier
  2918. // instead.
  2919. //----------------------------------------------------------------------------------------
  2920. TDescriptor TAbstractScriptableObject::BuildSpecifierForParent(const TAETransaction& t)
  2921.     {
  2922.     TAbstractScriptableObject* parent;
  2923.     TDescriptor result;
  2924.     
  2925.     //
  2926.     // If we have a parent, then ask it to build an object
  2927.     // specifier.  If we have no parent, then return a null
  2928.     // descriptor to indicate that this object may be accessed
  2929.     // via the null container.
  2930.     //
  2931.     parent = this->ParentObject(t);
  2932.     if(parent != nil)
  2933.         {
  2934.         result = parent->BuildObjectSpecifier(t);
  2935.         parent->DisposeDesignator();
  2936.         }
  2937.     
  2938.     return result;
  2939.     } // TAbstractScriptableObject::BuildSpecifierForParent 
  2940.  
  2941. //----------------------------------------------------------------------------------------
  2942. // TAbstractScriptableObject::BuildSimpleSpecifier
  2943. //----------------------------------------------------------------------------------------
  2944. TDescriptor TAbstractScriptableObject::BuildSimpleSpecifier(const TAETransaction& t)
  2945.     {
  2946.     return this->BuildObjectSpecifier(t);
  2947.     }
  2948.  
  2949. //----------------------------------------------------------------------------------------
  2950. // TAbstractScriptableObject::GetAECommandDispatcher:
  2951. //
  2952. // This method allows any object to specify some other object to send specific commands
  2953. // to; for example, the Finder sends delete commands to the trash object, since
  2954. // deleting a file with a script moves it to the trash.
  2955. //
  2956. // I was somewhat tempted to allow GetAECommandDispatcher to also change the
  2957. // command ID of the command being redirected, but I decided to keep it simple.
  2958. //----------------------------------------------------------------------------------------
  2959. TAbstractScriptableObject* TAbstractScriptableObject::GetAECommandDispatcher(const TAETransaction&, long /*commandID*/, long /*auxInfo*/, long& oneDispatchSelector)
  2960.     {
  2961.     oneDispatchSelector = 0;
  2962.     return nil;
  2963.     } // TAbstractScriptableObject::GetAECommandDispatcher
  2964.  
  2965. //----------------------------------------------------------------------------------------
  2966. // TAbstractScriptableObject::AECommandDispatch:
  2967. //----------------------------------------------------------------------------------------
  2968. TDescriptor TAbstractScriptableObject::AECommandDispatch(const TAETransaction& t, long aeCommandID, long auxInfo /* = 0 */)
  2969.     {
  2970.     TDescriptor result;
  2971.     long dispatchSelector = 0;
  2972.  
  2973.     //
  2974.     // First, decide if the command will operate on this object
  2975.     // or its representative 
  2976.     //    
  2977.     TAbstractScriptableObject* representative = nil;
  2978.     if(this->SendCommandToRepresentative(t, aeCommandID) == true)
  2979.         representative = this->RepresentativeScriptingObject(t);
  2980.     TAbstractScriptableObject* noun = representative ? representative : this;
  2981.     
  2982.     //
  2983.     // Next, decide if the command will be dispatched to the
  2984.     // noun, or to a different dispatch object.
  2985.     //
  2986.     TAbstractScriptableObject* dispatcher = noun->GetAECommandDispatcher(t, aeCommandID, auxInfo, dispatchSelector);
  2987.     
  2988.     if(dispatcher == nil)
  2989.         result = noun->AECommand(t, aeCommandID, nil, auxInfo);
  2990.     else
  2991.         {
  2992.         result = dispatcher->AECommand(t, aeCommandID, noun, auxInfo);
  2993.         dispatcher->DisposeDesignator();
  2994.         }
  2995.     
  2996.     if(representative != nil)
  2997.         representative->DisposeDesignator();
  2998.     
  2999.     return result;
  3000.     } // TAbstractScriptableObject::AECommandDispatch
  3001.     
  3002. //----------------------------------------------------------------------------------------
  3003. // TAbstractScriptableObject::AECommand:
  3004. //----------------------------------------------------------------------------------------
  3005. TDescriptor TAbstractScriptableObject::AECommand(const TAETransaction& /*transaction*/, long /*aeCommandID*/, TAbstractScriptableObject* /* auxObjects = nil */, long /* auxInfo = 0 */)
  3006.     {
  3007.     TDescriptor nothing;
  3008.     
  3009.     Throw(errAEEventNotHandled);
  3010.     
  3011.     return nothing;
  3012.     } // TAbstractScriptableObject::AECommand 
  3013.  
  3014. //----------------------------------------------------------------------------------------
  3015. // TAbstractScriptableObject::CreateNewElement:
  3016. //----------------------------------------------------------------------------------------
  3017. TAbstractScriptableObject* TAbstractScriptableObject::CreateNewElement(const TAETransaction& t, DescType newObjectClass, TDescriptor initialData, TDescriptor initialProperties, Boolean& usedInitialData, Boolean& usedInitialProperties)
  3018.     {
  3019.     TAbstractScriptableObject* newElement = nil;
  3020.     
  3021.     TAbstractScriptableObject* representative = nil;
  3022.     NOREGISTER(representative);
  3023.     OSErr representativeError = noErr;
  3024.     Try
  3025.         {
  3026.         representative = this->RepresentativeScriptingObject(t);
  3027.         if(representative != nil)
  3028.             newElement = representative->CreateNewElement(t, newObjectClass, initialData, initialProperties, usedInitialData, usedInitialProperties);
  3029.         }
  3030.     Catch(representativeError)
  3031.         {
  3032.         }
  3033.     if(representative != nil)
  3034.         representative->DisposeDesignator();
  3035.     FailErr(representativeError);
  3036.  
  3037.     if(newElement == nil)
  3038.         Throw(errAEEventNotHandled);
  3039.     
  3040.     return newElement;
  3041.     } // TAbstractScriptableObject::CreateNewElement 
  3042.  
  3043. #pragma segment CFrontCruft
  3044.